home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / TrackView.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-18  |  73.5 KB  |  2,331 lines  |  [TEXT/KAHL]

  1. /* TrackView.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "TrackView.h"
  31. #include "TrackObject.h"
  32. #include "Memory.h"
  33. #include "FrameObject.h"
  34. #include "Frequency.h"
  35. #include "EditImages.h"
  36. #include "StaffCalibration.h"
  37. #include "TrackDisplayScheduling.h"
  38. #include "Array.h"
  39. #include "EditCommandParameters.h"
  40. #include "Numbers.h"
  41. #include "TieTrackPixel.h"
  42. #include "Scrap.h"
  43. #include "Files.h"
  44. #include "BufferedFileInput.h"
  45. #include "BufferedFileOutput.h"
  46. #include "DataMunging.h"
  47. #include "MainWindowStuff.h"
  48. #include "LoadSaveNoteVectors.h"
  49. #include "Alert.h"
  50.  
  51.  
  52. /* so that tips of notes can be seen above last staff line */
  53. #define EDGESPACER (48)
  54.  
  55. /* so that you have space to add new notes */
  56. #define HORIZONTALEXTENTION (200)
  57.  
  58. /* width of the insertion point */
  59. #define INSERTIONPOINTWIDTH (2)
  60.  
  61. /* tie endpoint positioning correction values */
  62. #define TIESTARTXCORRECTION (11)
  63. #define TIESTARTYCORRECTION (9)
  64. #define TIEENDXCORRECTION (4)
  65. #define TIEENDYCORRECTION (9)
  66.  
  67. /* tie curve drawing parameters */
  68. #define NUMTIELINEINTERVALS (10)
  69. #define MAXTIEDEPTH (15)
  70.  
  71. /* the width of the box drawn for range selection */
  72. #define RANGESELECTTHICKNESS (3)
  73.  
  74.  
  75. #define MAGICSCRAPSTRING ("\xff\x00\x1f\xfe NoteRangeScrap")
  76.  
  77.  
  78. typedef enum
  79.     {
  80.         eTrackViewNoSelection EXECUTE(= -99),
  81.         eTrackViewSingleNoteSelection,
  82.         eTrackViewSingleCommandSelection,
  83.         eTrackViewRangeSelection
  84.     } SelectionModes;
  85.  
  86. typedef enum
  87.     {
  88.         eTrackViewNoUndo EXECUTE(= -5134),
  89.         eTrackViewUndoNoteInsertion,
  90.         eTrackViewUndoRangeInsertion,
  91.         eTrackViewUndoFromFile
  92.     } UndoChoices;
  93.  
  94. struct TrackViewRec
  95.     {
  96.         WinType*                            Window;
  97.         OrdType                                XLoc;
  98.         OrdType                                YLoc;
  99.         OrdType                                Width;
  100.         OrdType                                Height;
  101.         TrackObjectRec*                TrackObj;
  102.         MyBoolean                            CursorBarIsVisible;
  103.         OrdType                                CursorBarLoc;
  104.         long                                    PixelIndent;
  105.         long                                    VerticalOffset;
  106.  
  107.         SelectionModes                SelectionMode;
  108.         long                                    InsertionPointIndex; /* valid only for eTrackViewNoSelection */
  109.         NoteObjectRec*                SelectedNote; /* valid only for single selection */
  110.         long                                    SelectedNoteFrame; /* valid only for single selection */
  111.         long                                    RangeSelectStart; /* valid only for eTrackViewRangeSelection */
  112.         long                                    RangeSelectEnd; /* valid only for eTrackViewRangeSelection */
  113.  
  114.         UndoChoices                        UndoState;
  115.         long                                    UndoNoteInsertionFrameIndex; /* valid only for eTrackViewUndoNoteInsertion */
  116.         long                                    UndoNoteInsertionNoteIndex; /* valid only for eTrackViewUndoNoteInsertion */
  117.         long                                    UndoRangeStartIndex; /* valid only for eTrackViewUndoRangeInsertion */
  118.         long                                    UndoRangeElemCount; /* valid only for eTrackViewUndoRangeInsertion */
  119.         FileSpec*                            UndoTempFileLoc; /* valid only for eTrackViewUndoFromFile */
  120.         FileType*                            UndoTempFileDesc; /* valid only for eTrackViewUndoFromFile */
  121.  
  122.         TrackDispScheduleRec*    Schedule;
  123.     };
  124.  
  125.  
  126. static long                                StaffRefCount = 0;
  127. static short*                            MinorStaffList = NIL;
  128.  
  129.  
  130. /* create a new track view object */
  131. TrackViewRec*                        NewTrackView(struct TrackObjectRec* TrackObj, WinType* Window,
  132.                                                     OrdType X, OrdType Y, OrdType Width, OrdType Height)
  133.     {
  134.         TrackViewRec*                    View;
  135.         ArrayRec*                            BackgroundList;
  136.         long                                    Limit;
  137.         long                                    Scan;
  138.  
  139.         View = (TrackViewRec*)AllocPtrCanFail(sizeof(TrackViewRec),"TrackViewRec");
  140.         if (View == NIL)
  141.             {
  142.              FailurePoint1:
  143.                 return NIL;
  144.             }
  145.         View->Schedule = NewTrackDisplaySchedule(TrackObj);
  146.         if (View->Schedule == NIL)
  147.             {
  148.              FailurePoint3:
  149.                 ReleasePtr((char*)View);
  150.                 goto FailurePoint1;
  151.             }
  152.         BackgroundList = TrackObjectGetBackgroundList(TrackObj);
  153.         Limit = ArrayGetLength(BackgroundList);
  154.         for (Scan = 0; Scan < Limit; Scan += 1)
  155.             {
  156.                 if (!AddTrackToDisplaySchedule(View->Schedule,
  157.                     (TrackObjectRec*)ArrayGetElement(BackgroundList,Scan)))
  158.                     {
  159.                      FailurePoint4:
  160.                         goto FailurePoint3;
  161.                     }
  162.             }
  163.         if (!TrackObjectAddDependentView(TrackObj,View))
  164.             {
  165.              FailurePoint5:
  166.                 goto FailurePoint4;
  167.             }
  168.         for (Scan = 0; Scan < Limit; Scan += 1)
  169.             {
  170.                 if (!TrackObjectAddDependentView((TrackObjectRec*)ArrayGetElement(
  171.                     BackgroundList,Scan),View))
  172.                     {
  173.                      FailurePoint6:
  174.                         /* WARNING:  Scan must be valid from this loop */
  175.                         while (Scan > 0)
  176.                             {
  177.                                 Scan -= 1;
  178.                                 TrackObjectRemoveDependentView((TrackObjectRec*)ArrayGetElement(
  179.                                     BackgroundList,Scan),View);
  180.                             }
  181.                         TrackObjectRemoveDependentView(TrackObj,View);
  182.                         goto FailurePoint5;
  183.                     }
  184.             }
  185.         if (StaffRefCount == 0)
  186.             {
  187.                 MinorStaffList = GetMinorStaffList();
  188.                 if (MinorStaffList == NIL)
  189.                     {
  190.                         goto FailurePoint6;
  191.                     }
  192.             }
  193.         StaffRefCount += 1;
  194.         View->Window = Window;
  195.         View->XLoc = X;
  196.         View->YLoc = Y;
  197.         View->Width = Width;
  198.         View->Height = Height;
  199.         View->TrackObj = TrackObj;
  200.         View->PixelIndent = 0;
  201.         View->CursorBarIsVisible = False;
  202.         View->SelectionMode = eTrackViewNoSelection;
  203.         View->InsertionPointIndex = 0;
  204.         View->VerticalOffset = (MaxVerticalSize() - Height) / 2;
  205.         if (View->VerticalOffset < -EDGESPACER)
  206.             {
  207.                 View->VerticalOffset = -EDGESPACER;
  208.             }
  209.         View->VerticalOffset = (View->VerticalOffset / 4) * 4;
  210.         View->UndoState = eTrackViewNoUndo;
  211.         return View;
  212.     }
  213.  
  214.  
  215. /* dispose of the track view object */
  216. void                                        DisposeTrackView(TrackViewRec* View)
  217.     {
  218.         ArrayRec*                            BackgroundList;
  219.         long                                    Limit;
  220.         long                                    Scan;
  221.  
  222.         CheckPtrExistence(View);
  223.         TrackViewFlushUndoInfo(View);
  224.         BackgroundList = TrackObjectGetBackgroundList(View->TrackObj);
  225.         Limit = ArrayGetLength(BackgroundList);
  226.         for (Scan = 0; Scan < Limit; Scan += 1)
  227.             {
  228.                 TrackObjectRemoveDependentView((TrackObjectRec*)ArrayGetElement(
  229.                     BackgroundList,Scan),View);
  230.             }
  231.         TrackObjectRemoveDependentView(View->TrackObj,View);
  232.         DisposeTrackDisplaySchedule(View->Schedule);
  233.         StaffRefCount -= 1;
  234.         if (StaffRefCount == 0)
  235.             {
  236.                 ReleasePtr((char*)MinorStaffList);
  237.             }
  238.         ReleasePtr((char*)View);
  239.     }
  240.  
  241.  
  242. /* get the left edge of the track view area */
  243. OrdType                                    GetTrackViewXLoc(TrackViewRec* View)
  244.     {
  245.         CheckPtrExistence(View);
  246.         return View->XLoc;
  247.     }
  248.  
  249.  
  250. /* get the top edge of the track view area */
  251. OrdType                                    GetTrackViewYLoc(TrackViewRec* View)
  252.     {
  253.         CheckPtrExistence(View);
  254.         return View->YLoc;
  255.     }
  256.  
  257.  
  258. /* get the width of the track view area */
  259. OrdType                                    GetTrackViewWidth(TrackViewRec* View)
  260.     {
  261.         CheckPtrExistence(View);
  262.         return View->Width;
  263.     }
  264.  
  265.  
  266. /* get the height of the track view area */
  267. OrdType                                    GetTrackViewHeight(TrackViewRec* View)
  268.     {
  269.         CheckPtrExistence(View);
  270.         return View->Height;
  271.     }
  272.  
  273.  
  274. /* change the location of the track view area */
  275. void                                        SetTrackViewPosition(TrackViewRec* View, OrdType X, OrdType Y,
  276.                                                     OrdType Width, OrdType Height)
  277.     {
  278.         CheckPtrExistence(View);
  279.         View->VerticalOffset += (View->Height - Height) / 2;
  280.         if (View->VerticalOffset < -EDGESPACER)
  281.             {
  282.                 View->VerticalOffset = -EDGESPACER;
  283.             }
  284.         View->VerticalOffset = (View->VerticalOffset / 4) * 4;
  285.         View->XLoc = X;
  286.         View->YLoc = Y;
  287.         View->Width = Width;
  288.         View->Height = Height;
  289.         TrackViewRedrawAll(View);
  290.     }
  291.  
  292.  
  293. /* redraw the track view staff bars.  it assumes clipping rectangle has been */
  294. /* properly set up */
  295. void                                        TrackViewRedrawStaff(TrackViewRec* View, OrdType XStart,
  296.                                                     OrdType Width)
  297.     {
  298.         long                                    Scan;
  299.         short*                                MajorStaffList;
  300.  
  301.         CheckPtrExistence(View);
  302.         /* draw staff bars around C */
  303.         MajorStaffList = GetMajorStaffList();
  304.         for (Scan = GetMajorStaffListLength(); Scan >= 0; Scan -= 1)
  305.             {
  306.                 DrawLine(View->Window,eBlack,XStart,ConvertPitchToPixel(MajorStaffList[Scan],0)
  307.                     - View->VerticalOffset + View->YLoc,Width,0);
  308.             }
  309.         /* draw other staff bars */
  310.         for (Scan = PtrSize((char*)MinorStaffList) / sizeof(short) - 1; Scan >= 0; Scan -= 1)
  311.             {
  312.                 DrawLine(View->Window,eMediumGrey,XStart,ConvertPitchToPixel(
  313.                     MinorStaffList[Scan],0) - View->VerticalOffset + View->YLoc,Width,0);
  314.             }
  315.         /* draw all C lines */
  316.         for (Scan = 0; Scan <= (NUMNOTES - 1) / 2; Scan += 12)
  317.             {
  318.                 DrawLine(View->Window,eLightGrey,XStart,ConvertPitchToPixel(CENTERNOTE - Scan,0)
  319.                     - View->VerticalOffset + View->YLoc,Width,0);
  320.                 DrawLine(View->Window,eLightGrey,XStart,ConvertPitchToPixel(CENTERNOTE + Scan,0)
  321.                     - View->VerticalOffset + View->YLoc,Width,0);
  322.             }
  323.     }
  324.  
  325.  
  326. /* get the number of vertical degrees of freedom, for setting the vertical scroll bar */
  327. long                                        TrackViewGetVerticalDegreesOfFreedom(TrackViewRec* View)
  328.     {
  329.         long                                    ReturnValue;
  330.  
  331.         CheckPtrExistence(View);
  332.         ReturnValue = MaxVerticalSize() - View->Height + (2 * EDGESPACER);
  333.         if (ReturnValue < 0)
  334.             {
  335.                 ReturnValue = 0;
  336.             }
  337.         return ReturnValue;
  338.     }
  339.  
  340.  
  341. /* get the vertical offset for setting vertical scroll bar.  0 is top of score area. */
  342. long                                        TrackViewGetVerticalOffset(TrackViewRec* View)
  343.     {
  344.         CheckPtrExistence(View);
  345.         /* they want all positive numbers, so we add in EDGESPACER */
  346.         return View->VerticalOffset + EDGESPACER;
  347.     }
  348.  
  349.  
  350. /* hit test to see if the coordinates are within the track view area */
  351. MyBoolean                                TrackViewHitTest(TrackViewRec* View, OrdType X, OrdType Y)
  352.     {
  353.         CheckPtrExistence(View);
  354.         return (X >= View->XLoc) && (Y >= View->YLoc) && (X < View->XLoc + View->Width)
  355.             && (Y < View->YLoc + View->Height);
  356.     }
  357.  
  358.  
  359. /* change the vertical offset and redraw the track view area */
  360. void                                        TrackViewSetNewVerticalOffset(TrackViewRec* View, long Offset)
  361.     {
  362.         long                                    Delta;
  363.  
  364.         CheckPtrExistence(View);
  365.         TrackViewUndrawCursorBar(View);
  366.         /* do some bounds checking.  we don't use EDGESPACER since they are dealing */
  367.         /* in positive numbers, and so does TrackViewGetVerticalDegreesOfFreedom. */
  368.         if (Offset < 0)
  369.             {
  370.                 Offset = 0;
  371.             }
  372.         if (Offset > TrackViewGetVerticalDegreesOfFreedom(View) - 1)
  373.             {
  374.                 Offset = TrackViewGetVerticalDegreesOfFreedom(View) - 1;
  375.             }
  376.         /* they use positive numbers, but we need one with proper origin */
  377.         Offset -= EDGESPACER;
  378.         /* since we use patterns aligned to 2 and 4 pixels, keep things even so */
  379.         /* the patterns don't look weird */
  380.         Offset = (Offset / 4) * 4;
  381.         /* figure out how much to scroll by */
  382.         Delta = View->VerticalOffset - Offset;
  383.         if (Delta < ORDTYPEMIN)
  384.             {
  385.                 Delta = ORDTYPEMIN;
  386.             }
  387.         else if (Delta > ORDTYPEMAX)
  388.             {
  389.                 Delta = ORDTYPEMAX;
  390.             }
  391.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  392.         ScrollArea(View->Window,View->XLoc,View->YLoc,View->Width,View->Height,0,Delta);
  393.         if (Delta < 0)
  394.             {
  395.                 /* current offset < new offset, scroll up & open hole at bottom */
  396.                 AddClipRect(View->Window,View->XLoc,View->YLoc + View->Height + Delta
  397.                     - RANGESELECTTHICKNESS,View->Width,-Delta + RANGESELECTTHICKNESS);
  398.             }
  399.          else
  400.             {
  401.                 /* current offset > new offset, scroll down & open hole at top */
  402.                 AddClipRect(View->Window,View->XLoc,View->YLoc,View->Width,Delta
  403.                     + RANGESELECTTHICKNESS);
  404.             }
  405.         View->VerticalOffset = Offset;
  406.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  407.     }
  408.  
  409.  
  410. /* redraw the entire track view, including properly setting the clipping region. */
  411. void                                        TrackViewRedrawAll(TrackViewRec* View)
  412.     {
  413.         CheckPtrExistence(View);
  414.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  415.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  416.     }
  417.  
  418.  
  419. /* update the cursor and optionally draw the vertical (pitch) positioning bar */
  420. void                                        TrackViewUpdateMouseCursor(TrackViewRec* View,
  421.                                                     OrdType X, OrdType Y, MyBoolean DrawFunnyBarThing)
  422.     {
  423.         MyBoolean                            OnAFrameFlag;
  424.         long                                    Dummy;
  425.         OrdType                                NewCursorBar;
  426.  
  427.         CheckPtrExistence(View);
  428.         X -= View->XLoc;
  429.         Y -= View->YLoc;
  430.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  431.             &OnAFrameFlag,&Dummy))
  432.             {
  433.                 return;
  434.             }
  435.         if (DrawFunnyBarThing)
  436.             {
  437.                 NewCursorBar = ConvertPitchToPixel(ConvertPixelToPitch(Y + View->VerticalOffset),0);
  438.                 if ((NewCursorBar != View->CursorBarLoc) || !View->CursorBarIsVisible)
  439.                     {
  440.                         TrackViewUndrawCursorBar(View);
  441.                         View->CursorBarLoc = NewCursorBar;
  442.                         TrackViewDrawCursorBar(View);
  443.                     }
  444.             }
  445.         if (OnAFrameFlag)
  446.             {
  447.                 SetScoreOverlayCursor();
  448.             }
  449.          else
  450.             {
  451.                 SetScoreIntersticeCursor();
  452.             }
  453.     }
  454.  
  455.  
  456. /* the track data has been modified, so set some flags */
  457. void                                        TrackViewTrackObjectModified(TrackViewRec* View,
  458.                                                     TrackObjectRec* TrackObj, long Index)
  459.     {
  460.         CheckPtrExistence(View);
  461.         CheckPtrExistence(TrackObj);
  462.         TrackDisplayScheduleMarkChanged(View->Schedule,View->TrackObj,Index);
  463.     }
  464.  
  465.  
  466. /* another track has been deleted, so remove it from the background list */
  467. void                                        TrackViewObjectTrackDying(TrackViewRec* View,
  468.                                                     TrackObjectRec* TrackObj)
  469.     {
  470.         CheckPtrExistence(View);
  471.         CheckPtrExistence(TrackObj);
  472.         DeleteTrackFromDisplaySchedule(View->Schedule,TrackObj);
  473.     }
  474.  
  475.  
  476. /* insert a note at the specified mouse coordinate with the attributes */
  477. void                                        TrackViewAddNote(TrackViewRec* View,
  478.                                                     OrdType X, OrdType Y, unsigned long NoteAttributes)
  479.     {
  480.         MyBoolean                            AddToFrame;
  481.         long                                    Index;
  482.         NoteObjectRec*                Note;
  483.         unsigned long                    NoteSharpFlatTemp;
  484.         short                                    NotePitchTemp;
  485.  
  486.         CheckPtrExistence(View);
  487.         ERROR((NoteAttributes & eCommandFlag) != 0,PRERR(ForceAbort,
  488.             "TrackViewAddNote being used to insert command into score"));
  489.         TrackViewFlushUndoInfo(View);
  490.         X -= View->XLoc;
  491.         Y -= View->YLoc;
  492.         /* figure out where we are supposed to put this note. */
  493.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  494.             &AddToFrame,&Index))
  495.             {
  496.                 return;
  497.             }
  498.         /* construct the note to be added */
  499.         Note = NewNote();
  500.         if (Note == NIL)
  501.             {
  502.                 return;
  503.             }
  504.         SetUpNoteInfo(&NotePitchTemp,&NoteSharpFlatTemp,(NoteAttributes & eSharpModifier)
  505.             != 0,(NoteAttributes & eFlatModifier) != 0,Y + View->VerticalOffset);
  506.         PutNotePitch(Note,NotePitchTemp);
  507.         PutNoteDuration(Note,NoteAttributes & eDurationMask);
  508.         PutNoteDurationDivision(Note,NoteAttributes & eDivisionMask);
  509.         PutNoteDotStatus(Note,(NoteAttributes & eDotModifier) != 0);
  510.         PutNoteFlatOrSharpStatus(Note,NoteSharpFlatTemp);
  511.         PutNoteIsItARest(Note,(NoteAttributes & eRestModifier) != 0);
  512.         ERROR((NoteAttributes & ~(eSharpModifier | eFlatModifier | eDurationMask
  513.             | eDivisionMask | eDotModifier | eRestModifier)) != 0,PRERR(AllowResume,
  514.             "TrackViewAddNote:  some unknown bits in the note attributes word are set"));
  515.         /* add note to the appropriate place */
  516.         if (AddToFrame)
  517.             {
  518.                 FrameObjectRec*                Frame;
  519.  
  520.                 /* add to existing frame */
  521.                 Frame = TrackObjectGetFrame(View->TrackObj,Index);
  522.                 if (IsThisACommandFrame(Frame))
  523.                     {
  524.                         /* if it's a command frame, then insert note after it */
  525.                         Index += 1;
  526.                         goto InsertionPoint;
  527.                     }
  528.                 if (!AppendNoteToFrame(Frame,Note))
  529.                     {
  530.                      AppendFailurePoint1:
  531.                         DisposeNote(Note);
  532.                         return;
  533.                     }
  534.                 TrackObjectAltered(View->TrackObj,Index);
  535.                 /* remember the undo information */
  536.                 ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  537.                     "TrackViewAddNote:  undo info should have been purged"));
  538.                 View->UndoState = eTrackViewUndoNoteInsertion;
  539.                 View->UndoNoteInsertionFrameIndex = Index;
  540.                 View->UndoNoteInsertionNoteIndex = NumNotesInFrame(Frame) - 1;
  541.             }
  542.          else
  543.             {
  544.                 FrameObjectRec*                Frame;
  545.  
  546.                 /* create a new frame */
  547.              InsertionPoint:
  548.                 /* we hafta create a new frame */
  549.                 Frame = NewFrame();
  550.                 if (Frame == NIL)
  551.                     {
  552.                      InsertionFailurePoint1:
  553.                         goto AppendFailurePoint1;
  554.                     }
  555.                 if (!AppendNoteToFrame(Frame,Note))
  556.                     {
  557.                      InsertionFailurePoint2:
  558.                         DisposeFrameAndContents(Frame);
  559.                         goto InsertionFailurePoint1;
  560.                     }
  561.                 if (!TrackObjectInsertFrame(View->TrackObj,Index,Frame))
  562.                     {
  563.                      InsertionFailurePoint3:
  564.                         goto InsertionFailurePoint2;
  565.                     }
  566.                 /* remember the undo information */
  567.                 ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  568.                     "TrackViewAddNote:  undo info should have been purged"));
  569.                 View->UndoState = eTrackViewUndoNoteInsertion;
  570.                 View->UndoNoteInsertionFrameIndex = Index;
  571.                 View->UndoNoteInsertionNoteIndex = 0;
  572.                 /* we don't have to notify track of change because it knows already. */
  573.             }
  574.         /* adjust the insertion point */
  575.         View->SelectionMode = eTrackViewSingleNoteSelection;
  576.         View->SelectedNote = Note;
  577.         View->SelectedNoteFrame = Index;
  578.         /* redraw what needs to be redrawn.  this definitely needs to be fixed */
  579.         /* up since it's unnecessary to redraw the whole staff just to add a note. */
  580.         TrackViewRedrawAll(View);
  581.         View->CursorBarIsVisible = False; /* temporary */
  582.     }
  583.  
  584.  
  585. /* add a command at the specified mouse coordinates. */
  586. void                                        TrackViewAddCommand(TrackViewRec* View,
  587.                                                     OrdType X, OrdType Y, NoteCommands CommandOpcode)
  588.     {
  589.         MyBoolean                            AddToFrame;
  590.         long                                    Index;
  591.         NoteObjectRec*                Command;
  592.         FrameObjectRec*                Frame;
  593.  
  594.         CheckPtrExistence(View);
  595.         TrackViewFlushUndoInfo(View);
  596.         X -= View->XLoc;
  597.         Y -= View->YLoc;
  598.         /* figure out where we are supposed to put this note. */
  599.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  600.             &AddToFrame,&Index))
  601.             {
  602.                 return;
  603.             }
  604.         /* AddToFrame is ignored for adding commands */
  605.         /* construct the command to be added */
  606.         Command = NewCommand();
  607.         if (Command == NIL)
  608.             {
  609.                 return;
  610.             }
  611.         PutCommandOpcode(Command,CommandOpcode);
  612.         /* add command to the appropriate place */
  613.         /* create a new frame */
  614.         Frame = NewFrame();
  615.         if (Frame == NIL)
  616.             {
  617.              InsertionFailurePoint1:
  618.                 DisposeNote(Command);
  619.                 return;
  620.             }
  621.         if (!AppendNoteToFrame(Frame,Command))
  622.             {
  623.              InsertionFailurePoint2:
  624.                 DisposeFrameAndContents(Frame);
  625.                 goto InsertionFailurePoint1;
  626.             }
  627.         if (!TrackObjectInsertFrame(View->TrackObj,Index,Frame))
  628.             {
  629.              InsertionFailurePoint3:
  630.                 goto InsertionFailurePoint2;
  631.             }
  632.         /* remember the undo information */
  633.         ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  634.             "TrackViewAddCommand:  undo info should have been purged"));
  635.         View->UndoState = eTrackViewUndoNoteInsertion;
  636.         View->UndoNoteInsertionFrameIndex = Index;
  637.         View->UndoNoteInsertionNoteIndex = 0;
  638.         /* we don't have to notify track of change because it knows already. */
  639.         /* adjust the insertion point */
  640.         View->SelectionMode = eTrackViewSingleCommandSelection;
  641.         View->SelectedNote = Command;
  642.         View->SelectedNoteFrame = Index;
  643.         /* redraw what needs to be redrawn.  this definitely needs to be fixed */
  644.         /* up since it's unnecessary to redraw the whole staff just to add a command. */
  645.         TrackViewRedrawAll(View);
  646.         View->CursorBarIsVisible = False; /* temporary */
  647.     }
  648.  
  649.  
  650. /* erase the vertical (pitch) positioning bar */
  651. void                                        TrackViewUndrawCursorBar(TrackViewRec* View)
  652.     {
  653.         CheckPtrExistence(View);
  654.         if (View->CursorBarIsVisible)
  655.             {
  656.                 SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  657.                 AddClipRect(View->Window,View->XLoc,View->YLoc - View->VerticalOffset
  658.                     + View->CursorBarLoc - 1,View->Width,3);
  659.                 DrawBoxErase(View->Window,View->XLoc,View->YLoc - View->VerticalOffset
  660.                     + View->CursorBarLoc - 1,View->Width,3);
  661.                 TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  662.             }
  663.         View->CursorBarIsVisible = False;
  664.     }
  665.  
  666.  
  667. /* draw the vertical (pitch) positioning bar.  this assumes that it has been */
  668. /* previously undrawn (i.e. it doesn't erase any existing bars) */
  669. void                                        TrackViewDrawCursorBar(TrackViewRec* View)
  670.     {
  671.         CheckPtrExistence(View);
  672.         View->CursorBarIsVisible = True;
  673.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  674.         DrawBoxPaint(View->Window,eMediumGrey,View->XLoc,View->YLoc - View->VerticalOffset
  675.             + View->CursorBarLoc - 1,View->Width,3);
  676.     }
  677.  
  678.  
  679. /* draw a cute little paraboloid thing */
  680. static void                            DrawTieLine(WinType* ScreenID, Patterns Pattern,
  681.                                                     OrdType StartX, OrdType StartY, OrdType Width, OrdType Height)
  682.     {
  683.         long                                    Index;
  684.         OrdType                                PixelXLoc[NUMTIELINEINTERVALS];
  685.         OrdType                                PixelYLoc[NUMTIELINEINTERVALS];
  686.  
  687.         /* generate coordinates */
  688.         for (Index = 0; Index < NUMTIELINEINTERVALS; Index += 1)
  689.             {
  690.                 double                                FuncX;
  691.  
  692.                 FuncX = 2 * ((double)Index / (NUMTIELINEINTERVALS - 1)) - 1;
  693.                 PixelXLoc[Index] = Width * ((double)Index / (NUMTIELINEINTERVALS - 1));
  694.                 PixelYLoc[Index] = Height * ((double)Index / (NUMTIELINEINTERVALS - 1))
  695.                     + ((1 - FuncX * FuncX) * MAXTIEDEPTH);
  696.             }
  697.         /* draw the lines */
  698.         for (Index = 0; Index < NUMTIELINEINTERVALS - 1; Index += 1)
  699.             {
  700.                 OrdType                                PosX = StartX + PixelXLoc[Index];
  701.                 OrdType                                PosY = StartY + PixelYLoc[Index];
  702.  
  703.                 DrawLine(ScreenID,Pattern,PosX,PosY,(StartX + PixelXLoc[Index + 1]) - PosX,
  704.                     (StartY + PixelYLoc[Index + 1]) - PosY);
  705.             }
  706.     }
  707.  
  708.  
  709. /* redraw the whole track view, but don't mess with the clipping region.  XStart is */
  710. /* is in window coordinates, not local coordinates */
  711. void                                        TrackViewRedrawDontSetClip(TrackViewRec* View, OrdType XStart,
  712.                                                     OrdType Width)
  713.     {
  714.         long                                    NumTracks;
  715.         long                                    TrackScan;
  716.         long                                    CenterNotePixel;
  717.         FontType                            Font;
  718.         OrdType                                FontHeight;
  719.  
  720.         CheckPtrExistence(View);
  721.         /* erase the drawing area */
  722.         DrawBoxErase(View->Window,XStart,View->YLoc,Width,View->Height);
  723.         /* draw the staff */
  724.         TrackViewRedrawStaff(View,XStart,Width);
  725.         /* now we have to draw the notes */
  726.         CenterNotePixel = View->YLoc - View->VerticalOffset + GetCenterNotePixel();
  727.         Font = GetScreenFont();
  728.         FontHeight = GetFontHeight(Font,9);
  729.  
  730.         /* draw ties first, so they are under the notes */
  731.         {
  732.             TieIntersectListRec*    TieList;
  733.  
  734.             TieList = TrackDisplayGetTieIntervalList(View->Schedule,View->PixelIndent,Width);
  735.             if (TieList != NIL)
  736.                 {
  737.                     long                                    TieLimit;
  738.                     long                                    TieScan;
  739.  
  740.                     TieLimit = GetTieTrackIntersectListLength(TieList);
  741.                     for (TieScan = 0; TieScan < TieLimit; TieScan += 1)
  742.                         {
  743.                             long                                    StartX;
  744.                             long                                    StartY;
  745.                             long                                    EndX;
  746.                             long                                    EndY;
  747.  
  748.                             GetTieTrackIntersectElement(TieList,TieScan,&StartX,&StartY,&EndX,&EndY);
  749.                             DrawTieLine(View->Window,eBlack,(StartX + TIESTARTXCORRECTION)
  750.                                 - View->PixelIndent + View->XLoc,(StartY + TIESTARTYCORRECTION)
  751.                                 + View->YLoc - View->VerticalOffset,(EndX + TIEENDXCORRECTION)
  752.                                 - (StartX + TIESTARTXCORRECTION),(EndY + TIEENDYCORRECTION)
  753.                                 - (StartY + TIESTARTYCORRECTION));
  754.                         }
  755.                     DisposeTieTrackIntersectList(TieList);
  756.                 }
  757.         }
  758.  
  759.         /* draw the notes */
  760.         NumTracks = TrackDisplayGetNumTracks(View->Schedule);
  761.         /* note the less than or EQUAL to NumTracks in the loop... */
  762.         /* see note inside loop about why */
  763.         for (TrackScan = 0; TrackScan <= NumTracks; TrackScan += 1)
  764.             {
  765.                 TrackObjectRec*                TrackObj;
  766.                 long                                    ActualTrackIndex;
  767.  
  768.                 /* we want to draw our track, but we want to draw it last.  to do this, */
  769.                 /* we won't draw it when it comes around normally, but we'll loop one extra */
  770.                 /* (fake) time, during which we won't do the normal get track but instead, */
  771.                 /* we'll just use our own track.  not especially elegant, but it works */
  772.                 if (TrackScan < NumTracks)
  773.                     {
  774.                         TrackObj = TrackDisplayGetParticularTrack(View->Schedule,TrackScan);
  775.                     }
  776.                  else
  777.                     {
  778.                         TrackObj = View->TrackObj;
  779.                     }
  780.                 ActualTrackIndex = TrackDisplayGetTrackIndex(View->Schedule,TrackObj);
  781.                 if ((TrackObj != View->TrackObj) || (TrackScan == NumTracks))
  782.                     {
  783.                         MyBoolean                            Idiot;
  784.                         long                                    Position;
  785.  
  786.                         if (TrackDisplayPixelToIndex(View->Schedule,TrackObj,XStart
  787.                             + View->PixelIndent,&Idiot,&Position))
  788.                             {
  789.                                 long                                    Limit;
  790.                                 long                                    Scan;
  791.  
  792.                                 /* find out how much to draw.  this definitely needs to be */
  793.                                 /* fixed since there is no reason to draw frames until the */
  794.                                 /* end of the entire track */
  795.                                 Limit = TrackObjectGetNumFrames(TrackObj);
  796.  
  797.                                 if (Position > 0)
  798.                                     {
  799.                                         /* this draws the note just off the left edge of the */
  800.                                         /* screen to fix some update region alignment problems. */
  801.                                         Position -= 1;
  802.                                     }
  803.  
  804.                                 /* draw the insertion point, if there is one */
  805.                                 if ((TrackObj == View->TrackObj) && (View->SelectionMode
  806.                                     == eTrackViewNoSelection))
  807.                                     {
  808.                                         long                        TotalNumFrames;
  809.  
  810.                                         TotalNumFrames = TrackObjectGetNumFrames(TrackObj);
  811.                                         if (View->InsertionPointIndex < TotalNumFrames)
  812.                                             {
  813.                                                 long                        InsertionPixel;
  814.  
  815.                                                 /* draw the selection before it's corresponding frame */
  816.                                                 if (TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  817.                                                     View->InsertionPointIndex,&InsertionPixel))
  818.                                                     {
  819.                                                         InsertionPixel = View->XLoc - INSERTIONPOINTWIDTH / 2
  820.                                                             + InsertionPixel - View->PixelIndent;
  821.                                                         if (InsertionPixel < ORDTYPEMIN / 2)
  822.                                                             {
  823.                                                                 InsertionPixel = ORDTYPEMIN / 2;
  824.                                                             }
  825.                                                         if (InsertionPixel > ORDTYPEMAX / 2)
  826.                                                             {
  827.                                                                 InsertionPixel = ORDTYPEMAX / 2;
  828.                                                             }
  829.                                                         DrawBoxPaint(View->Window,eBlack,InsertionPixel,
  830.                                                             View->YLoc,INSERTIONPOINTWIDTH,View->Height);
  831.                                                     }
  832.                                             }
  833.                                         else if (TotalNumFrames > 0)
  834.                                             {
  835.                                                 long                        InsertionPixel;
  836.  
  837.                                                 /* oops, no frame, so draw it after the last frame */
  838.                                                 if (TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  839.                                                     TrackObjectGetNumFrames(TrackObj) - 1,&InsertionPixel))
  840.                                                     {
  841.                                                         InsertionPixel += WidthOfFrameAndDraw(View->Window,
  842.                                                             0,0,0,0,0,TrackObjectGetFrame(TrackObj,TotalNumFrames - 1),
  843.                                                             False/*don't draw*/,False);
  844.                                                         InsertionPixel = View->XLoc - INSERTIONPOINTWIDTH / 2
  845.                                                             + InsertionPixel + EXTERNALSEPARATION - View->PixelIndent;
  846.                                                         if (InsertionPixel < ORDTYPEMIN / 2)
  847.                                                             {
  848.                                                                 InsertionPixel = ORDTYPEMIN / 2;
  849.                                                             }
  850.                                                         if (InsertionPixel > ORDTYPEMAX / 2)
  851.                                                             {
  852.                                                                 InsertionPixel = ORDTYPEMAX / 2;
  853.                                                             }
  854.                                                         DrawBoxPaint(View->Window,eBlack,InsertionPixel,View->YLoc,
  855.                                                             INSERTIONPOINTWIDTH,View->Height);
  856.                                                     }
  857.                                             }
  858.                                         else
  859.                                             {
  860.                                                 /* oops, no frames at all, so just draw it at the beginning */
  861.                                                 /* oh, well, it doesn't get drawn... should fix. (not that */
  862.                                                 /* there's any doubt where an insertion would occur...) */
  863.                                             }
  864.                                     }
  865.  
  866.                                 /* draw all of the frames */
  867.                                 for (Scan = Position; Scan < Limit; Scan += 1)
  868.                                     {
  869.                                         long                                    PixelIndex;
  870.                                         OrdType                                TheFrameWidth EXECUTE(= -8181);
  871.  
  872.                                         /* see if we can draw.  if TrackDisplayIndexToPixel returns false, */
  873.                                         /* then it just won't be drawn.  if TrackDisplayShouldWeDrawIt */
  874.                                         /* returns False, then don't draw because it isn't scheduled. */
  875.                                         if (TrackDisplayIndexToPixel(View->Schedule,ActualTrackIndex,Scan,
  876.                                             &PixelIndex) && TrackDisplayShouldWeDrawIt(View->Schedule,
  877.                                             ActualTrackIndex,Scan))
  878.                                             {
  879.                                                 FrameObjectRec*                Frame;
  880.  
  881.                                                 /* escape if we have gone past the end of the window */
  882.                                                 if (PixelIndex - (View->PixelIndent - View->XLoc)
  883.                                                     - LEFTNOTEEDGEINSET >= XStart + Width)
  884.                                                     {
  885.                                                         goto DonePoint;
  886.                                                     }
  887.  
  888.                                                 /* get the frame to draw */
  889.                                                 Frame = TrackObjectGetFrame(TrackObj,Scan);
  890.  
  891.                                                 /* this section is for stuff that only works in */
  892.                                                 /* the current track */
  893.                                                 if (TrackObj == View->TrackObj)
  894.                                                     {
  895.                                                         long                            MeasureBarIndex;
  896.  
  897.                                                         /* if we should draw a measure bar, then do so.  this */
  898.                                                         /* is done before drawing the notes so that the notes */
  899.                                                         /* will appear on top of the measure bar numbers if */
  900.                                                         /* there is an overwrite */
  901.  
  902.                                                         /* draw the measure bar */
  903.                                                         MeasureBarIndex = TrackDisplayMeasureBarIndex(
  904.                                                             View->Schedule,Scan);
  905.                                                         if (MeasureBarIndex != -1)
  906.                                                             {
  907.                                                                 char*                            IndexText;
  908.                                                                 Patterns                    HowToDraw;
  909.  
  910.                                                                 if (TrackDisplayShouldMeasureBarBeGreyed(
  911.                                                                     View->Schedule,Scan))
  912.                                                                     {
  913.                                                                         HowToDraw = eMediumGrey;
  914.                                                                     }
  915.                                                                  else
  916.                                                                     {
  917.                                                                         HowToDraw = eBlack;
  918.                                                                     }
  919.                                                                 /* actually something to be drawn */
  920.                                                                 DrawLine(View->Window,HowToDraw,PixelIndex - 4/*!*/
  921.                                                                     - View->PixelIndent + View->XLoc,View->YLoc
  922.                                                                     - View->VerticalOffset,0,MaxVerticalSize());
  923.                                                                 IndexText = IntegerToString(MeasureBarIndex);
  924.                                                                 if (IndexText != NIL)
  925.                                                                     {
  926.                                                                         DrawTextLine(View->Window,GetScreenFont(),9,
  927.                                                                             IndexText,PtrSize(IndexText),PixelIndex - 4/*!*/
  928.                                                                             - View->PixelIndent + View->XLoc - (LengthOfText(
  929.                                                                             GetScreenFont(),9,IndexText,PtrSize(IndexText),
  930.                                                                             ePlain) / 2),CenterNotePixel - (GetFontHeight(
  931.                                                                             GetScreenFont(),9) / 2),ePlain);
  932.                                                                         ReleasePtr(IndexText);
  933.                                                                     }
  934.                                                             }
  935.                                                     }
  936.  
  937.                                                 /* draw the notes */
  938.                                                 TheFrameWidth = WidthOfFrameAndDraw(View->Window,PixelIndex
  939.                                                     - View->PixelIndent + View->XLoc,CenterNotePixel,Font,9,
  940.                                                     FontHeight,Frame,True/*draw*/,
  941.                                                     (TrackObj != View->TrackObj)/*greyed*/);
  942.  
  943.                                                 /* draw any hilighting for selected items */
  944.                                                 switch (View->SelectionMode)
  945.                                                     {
  946.                                                         default:
  947.                                                             EXECUTE(PRERR(ForceAbort,
  948.                                                                 "TrackViewRedrawDontSetClip:  bad selection mode"));
  949.                                                             break;
  950.                                                         case eTrackViewNoSelection:
  951.                                                             break;
  952.                                                         case eTrackViewSingleNoteSelection:
  953.                                                             {
  954.                                                                 long                            FrameEnd;
  955.                                                                 long                            Scan;
  956.  
  957.                                                                 FrameEnd = NumNotesInFrame(Frame);
  958.                                                                 Scan = 0;
  959.                                                                 while (Scan < FrameEnd)
  960.                                                                     {
  961.                                                                         if (GetNoteFromFrame(Frame,Scan)
  962.                                                                             == View->SelectedNote)
  963.                                                                             {
  964.                                                                                 DrawBoxFrame(View->Window,eMediumGrey,
  965.                                                                                     PixelIndex - View->PixelIndent + View->XLoc
  966.                                                                                     + (Scan * INTERNALSEPARATION),View->YLoc
  967.                                                                                     - View->VerticalOffset,ICONWIDTH,
  968.                                                                                     MaxVerticalSize());
  969.                                                                                 DrawBoxFrame(View->Window,eMediumGrey,
  970.                                                                                     PixelIndex - View->PixelIndent + View->XLoc
  971.                                                                                     + (Scan * INTERNALSEPARATION) + 1,View->YLoc
  972.                                                                                     - View->VerticalOffset + 1,ICONWIDTH - 2,
  973.                                                                                     MaxVerticalSize() - 2);
  974.                                                                                 goto SingleNoteSelectDonePoint;
  975.                                                                             }
  976.                                                                         Scan += 1;
  977.                                                                     }
  978.                                                             }
  979.                                                          SingleNoteSelectDonePoint:
  980.                                                             break;
  981.                                                         case eTrackViewSingleCommandSelection:
  982.                                                             if (IsThisACommandFrame(Frame))
  983.                                                                 {
  984.                                                                     if (View->SelectedNote == GetNoteFromFrame(Frame,0))
  985.                                                                         {
  986.                                                                             DrawBoxFrame(View->Window,eMediumGrey,PixelIndex
  987.                                                                                 - View->PixelIndent + View->XLoc,View->YLoc
  988.                                                                                 - View->VerticalOffset,TheFrameWidth,
  989.                                                                                 MaxVerticalSize());
  990.                                                                             DrawBoxFrame(View->Window,eMediumGrey,PixelIndex
  991.                                                                                 - View->PixelIndent + View->XLoc + 1,View->YLoc
  992.                                                                                 - View->VerticalOffset + 1,TheFrameWidth - 2,
  993.                                                                                 MaxVerticalSize() - 2);
  994.                                                                         }
  995.                                                                 }
  996.                                                             break;
  997.                                                         case eTrackViewRangeSelection:
  998.                                                             break;
  999.                                                     }
  1000.                                             }
  1001.                                     } /* end of frame scan */
  1002.                                 /* jump here when end of visible note series is reached */
  1003.                              DonePoint:
  1004.                                 ;
  1005.                             }
  1006.                     }
  1007.             } /* end of track scan */
  1008.  
  1009.         /* draw selection box */
  1010.         if (View->SelectionMode == eTrackViewRangeSelection)
  1011.             {
  1012.                 long                            StartPixelIndex;
  1013.                 long                            EndPixelIndex;
  1014.                 long                            OurTrackIndex;
  1015.  
  1016.                 OurTrackIndex = TrackDisplayGetTrackIndex(View->Schedule,View->TrackObj);
  1017.                 ERROR(View->RangeSelectStart >= View->RangeSelectEnd,
  1018.                     PRERR(ForceAbort,"TrackViewRedrawDontSetClip:  "
  1019.                     "range selection boundaries are invalid"));
  1020.  
  1021.                 if (!TrackDisplayIndexToPixel(View->Schedule,OurTrackIndex,
  1022.                     View->RangeSelectStart,&StartPixelIndex))
  1023.                     {
  1024.                         return;
  1025.                     }
  1026.                 StartPixelIndex += (View->XLoc - View->PixelIndent); /* normalize to screen */
  1027.                 if (StartPixelIndex < ORDTYPEMIN / 2)
  1028.                     {
  1029.                         StartPixelIndex = ORDTYPEMIN / 2;
  1030.                     }
  1031.                 if (StartPixelIndex > ORDTYPEMAX / 2)
  1032.                     {
  1033.                         StartPixelIndex = ORDTYPEMAX / 2;
  1034.                     }
  1035.  
  1036.                 if (!TrackDisplayIndexToPixel(View->Schedule,OurTrackIndex,
  1037.                     View->RangeSelectEnd - 1,&EndPixelIndex))
  1038.                     {
  1039.                         return;
  1040.                     }
  1041.                 EndPixelIndex += WidthOfFrameAndDraw(View->Window,0,0,0,0,0,
  1042.                     TrackObjectGetFrame(View->TrackObj,View->RangeSelectEnd - 1),
  1043.                     False/*nodraw*/,False);
  1044.                 EndPixelIndex += (View->XLoc - View->PixelIndent); /* normalize to screen */
  1045.                 if (EndPixelIndex < ORDTYPEMIN / 2)
  1046.                     {
  1047.                         EndPixelIndex = ORDTYPEMIN / 2;
  1048.                     }
  1049.                 if (EndPixelIndex > ORDTYPEMAX / 2)
  1050.                     {
  1051.                         EndPixelIndex = ORDTYPEMAX / 2;
  1052.                     }
  1053.  
  1054.                 /* draw upper and lower edges of bounding box */
  1055.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc,EndPixelIndex
  1056.                     - StartPixelIndex + EXTERNALSEPARATION,RANGESELECTTHICKNESS);
  1057.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc + View->Height
  1058.                     - RANGESELECTTHICKNESS,EndPixelIndex - StartPixelIndex + EXTERNALSEPARATION,
  1059.                     RANGESELECTTHICKNESS);
  1060.  
  1061.                 /* draw left edge of bounding box */
  1062.                 DrawBoxPaint(View->Window,eBlack,StartPixelIndex,View->YLoc,
  1063.                     RANGESELECTTHICKNESS,View->Height);
  1064.  
  1065.                 /* draw right edge of bounding box */
  1066.                 DrawBoxPaint(View->Window,eBlack,EndPixelIndex + EXTERNALSEPARATION,
  1067.                     View->YLoc,RANGESELECTTHICKNESS,View->Height);
  1068.             }
  1069.     }
  1070.  
  1071.  
  1072. /* get the horizontal offset from the start of the track, in pixels */
  1073. long                                        TrackViewGetHorizontalOffset(TrackViewRec* View)
  1074.     {
  1075.         CheckPtrExistence(View);
  1076.         return View->PixelIndent;
  1077.     }
  1078.  
  1079.  
  1080. /* get the horizontal extent of the track (in pixels) for setting the scroll bar */
  1081. long                                        TrackViewGetHorizontalDegreesOfFreedom(TrackViewRec* View)
  1082.     {
  1083.         long                                    Temp;
  1084.  
  1085.         CheckPtrExistence(View);
  1086.         if (!TrackDisplayGetTotalLength(View->Schedule,&Temp))
  1087.             {
  1088.                 return 0;
  1089.             }
  1090.         Temp = Temp - View->Width + HORIZONTALEXTENTION;
  1091.         if (Temp < 0)
  1092.             {
  1093.                 Temp = 0;
  1094.             }
  1095.         return Temp;
  1096.     }
  1097.  
  1098.  
  1099. /* change the horizontal position of the track display and redraw */
  1100. void                                        TrackViewSetNewHorizontalOffset(TrackViewRec* View, long Offset)
  1101.     {
  1102.         long                                    Delta;
  1103.  
  1104.         CheckPtrExistence(View);
  1105.         TrackViewUndrawCursorBar(View);
  1106.         /* do some bounds checking. */
  1107.         if (Offset < 0)
  1108.             {
  1109.                 Offset = 0;
  1110.             }
  1111.         if (Offset > TrackViewGetHorizontalDegreesOfFreedom(View) - 1)
  1112.             {
  1113.                 Offset = TrackViewGetHorizontalDegreesOfFreedom(View) - 1;
  1114.             }
  1115.         /* since we use patterns aligned to 2 and 4 pixels, keep things even so */
  1116.         /* the patterns don't look weird */
  1117.         Offset = (Offset / 4) * 4;
  1118.         /* figure out how much to shift by */
  1119.         Delta = View->PixelIndent - Offset;
  1120.         if (Delta < ORDTYPEMIN)
  1121.             {
  1122.                 Delta = ORDTYPEMIN;
  1123.             }
  1124.         else if (Delta > ORDTYPEMAX)
  1125.             {
  1126.                 Delta = ORDTYPEMAX;
  1127.             }
  1128.         SetClipRect(View->Window,View->XLoc,View->YLoc,View->Width,View->Height);
  1129.         ScrollArea(View->Window,View->XLoc,View->YLoc,View->Width,View->Height,Delta,0);
  1130.         if (Delta < 0)
  1131.             {
  1132.                 /* current offset < new offset, scroll left & open hole at right */
  1133.                 AddClipRect(View->Window,View->XLoc + View->Width + Delta,View->YLoc,
  1134.                     -Delta,View->Height);
  1135.             }
  1136.          else
  1137.             {
  1138.                 /* current offset > new offset, scroll right & open hole at left */
  1139.                 AddClipRect(View->Window,View->XLoc,View->YLoc,Delta,View->Height);
  1140.             }
  1141.         View->PixelIndent = Offset;
  1142.         TrackViewRedrawDontSetClip(View,View->XLoc,View->Width);
  1143.     }
  1144.  
  1145.  
  1146. /* try to select a single note, if there is one, at the specified mouse location */
  1147. void                                        TrackViewTrySingleNoteSelection(TrackViewRec* View,
  1148.                                                     OrdType X, OrdType Y)
  1149.     {
  1150.         NoteObjectRec*                Note;
  1151.         MyBoolean                            CommandFlag;
  1152.         long                                    FrameIndex;
  1153.  
  1154.         CheckPtrExistence(View);
  1155.         X -= View->XLoc;
  1156.         Y -= View->YLoc;
  1157.         Note = TrackDisplayGetUnderlyingNote(View->Schedule,TrackDisplayGetTrackIndex(
  1158.             View->Schedule,View->TrackObj),&CommandFlag,X + View->PixelIndent,&FrameIndex);
  1159.         if (Note != NIL)
  1160.             {
  1161.                 if (CommandFlag)
  1162.                     {
  1163.                         View->SelectionMode = eTrackViewSingleCommandSelection;
  1164.                     }
  1165.                  else
  1166.                     {
  1167.                         View->SelectionMode = eTrackViewSingleNoteSelection;
  1168.                     }
  1169.                 View->SelectedNote = Note;
  1170.                 View->SelectedNoteFrame = FrameIndex;
  1171.             }
  1172.          else
  1173.             {
  1174.                 View->SelectionMode = eTrackViewNoSelection;
  1175.                 View->InsertionPointIndex = FrameIndex;
  1176.                 ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1177.                     PRERR(ForceAbort,"TrackViewTrySingleNoteSelection:  insertion point beyond end of track"));
  1178.             }
  1179.         TrackViewUndrawCursorBar(View);
  1180.         TrackViewRedrawAll(View);
  1181.     }
  1182.  
  1183.  
  1184. /* is the current selection a single note? */
  1185. MyBoolean                                TrackViewIsASingleNoteSelected(TrackViewRec* View)
  1186.     {
  1187.         CheckPtrExistence(View);
  1188.         return (View->SelectionMode == eTrackViewSingleNoteSelection);
  1189.     }
  1190.  
  1191.  
  1192. /* is the current selection a single command? */
  1193. MyBoolean                                TrackViewIsASingleCommandSelected(TrackViewRec* View)
  1194.     {
  1195.         CheckPtrExistence(View);
  1196.         return (View->SelectionMode == eTrackViewSingleCommandSelection);
  1197.     }
  1198.  
  1199.  
  1200. /* is a range of frames selected? */
  1201. MyBoolean                                TrackViewIsARangeSelected(TrackViewRec* View)
  1202.     {
  1203.         CheckPtrExistence(View);
  1204.         return (View->SelectionMode == eTrackViewRangeSelection);
  1205.     }
  1206.  
  1207.  
  1208. /* is nothing selected, and thus there is an insertion point? */
  1209. MyBoolean                                TrackViewIsThereInsertionPoint(TrackViewRec* View)
  1210.     {
  1211.         CheckPtrExistence(View);
  1212.         return (View->SelectionMode == eTrackViewNoSelection);
  1213.     }
  1214.  
  1215.  
  1216. /* get the frame index of the insertion point.  it is an error if there is no */
  1217. /* valid insertion point */
  1218. long                                        TrackViewGetInsertionPointIndex(TrackViewRec* View)
  1219.     {
  1220.         CheckPtrExistence(View);
  1221.         ERROR(View->SelectionMode != eTrackViewNoSelection,PRERR(ForceAbort,
  1222.             "TrackViewGetInsertionPointIndex:  there is no valid insertion point"));
  1223.         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1224.             PRERR(ForceAbort,"TrackViewGetInsertionPointIndex:  insertion point beyond end of track"));
  1225.         return View->InsertionPointIndex;
  1226.     }
  1227.  
  1228.  
  1229. /* get the beginning of a selection range.  it is an error if a range is not selected */
  1230. long                                        TrackViewGetRangeStart(TrackViewRec* View)
  1231.     {
  1232.         CheckPtrExistence(View);
  1233.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1234.             "TrackViewGetRangeStart:  there is no valid range selection"));
  1235.         return View->RangeSelectStart;
  1236.     }
  1237.  
  1238.  
  1239. /* get the frame after the end of a selection range.  it is an error if there is */
  1240. /* no selected range. */
  1241. long                                        TrackViewGetRangeEndPlusOne(TrackViewRec* View)
  1242.     {
  1243.         CheckPtrExistence(View);
  1244.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1245.             "TrackViewGetRangeEndPlusOne:  there is no valid range selection"));
  1246.         return View->RangeSelectEnd;
  1247.     }
  1248.  
  1249.  
  1250. /* get the frame number of a single note or command selection */
  1251. long                                        TrackViewGetSingleNoteSelectionFrameNumber(TrackViewRec* View)
  1252.     {
  1253.         CheckPtrExistence(View);
  1254.         ERROR(!TrackViewIsASingleNoteSelected(View)
  1255.             && !TrackViewIsASingleCommandSelected(View),PRERR(ForceAbort,
  1256.             "TrackViewGetSingleNoteSelectionFrameNumber:  no single note/command selection"));
  1257.         return View->SelectedNoteFrame;
  1258.     }
  1259.  
  1260.  
  1261. /* delete the selected single note or command.  it is an error if no single note */
  1262. /* or command is selected */
  1263. void                                        TrackViewDeleteSingleNoteOrCommand(TrackViewRec* View)
  1264.     {
  1265.         FrameObjectRec*                Frame;
  1266.         long                                    Limit;
  1267.         long                                    Scan;
  1268.  
  1269.         CheckPtrExistence(View);
  1270.         TrackViewFlushUndoInfo(View);
  1271.         ERROR((View->SelectionMode != eTrackViewSingleNoteSelection)
  1272.             && (View->SelectionMode != eTrackViewSingleCommandSelection),PRERR(ForceAbort,
  1273.             "TrackViewDeleteSingleNote:  no single note is selected"));
  1274.         if (!TrackViewBuildFullUndoBackingStore(View))
  1275.             {
  1276.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  1277.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  1278.                     {
  1279.                         default:
  1280.                             EXECUTE(PRERR(ForceAbort,
  1281.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  1282.                             break;
  1283.                         case eYes:
  1284.                             break;
  1285.                         case eNo:
  1286.                             return; /* abort now */
  1287.                     }
  1288.             }
  1289.         Frame = TrackObjectGetFrame(View->TrackObj,View->SelectedNoteFrame);
  1290.         CheckPtrExistence(Frame);
  1291.         Limit = NumNotesInFrame(Frame);
  1292.         for (Scan = 0; Scan < Limit; Scan += 1)
  1293.             {
  1294.                 if (View->SelectedNote == GetNoteFromFrame(Frame,Scan))
  1295.                     {
  1296.                         /* we found the note to delete */
  1297.                         /* zap ties to this note */
  1298.                         TrackObjectNullifyTies(View->TrackObj,View->SelectedNote);
  1299.                         /* indicate that stuff needs to be redrawn */
  1300.                         TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1301.                         /* now do the actual deletion */
  1302.                         if (NumNotesInFrame(Frame) == 1)
  1303.                             {
  1304.                                 /* since this is the only note in the frame, we'll just delete the */
  1305.                                 /* whole frame. */
  1306.                                 TrackObjectDeleteFrameRun(View->TrackObj,View->SelectedNoteFrame,1);
  1307.                             }
  1308.                          else
  1309.                             {
  1310.                                 /* there are other notes in the frame, so just delete this one note */
  1311.                                 if (!DeleteNoteFromFrame(Frame,Scan))
  1312.                                     {
  1313.                                         /* failed */
  1314.                                         return;
  1315.                                     }
  1316.                                 DisposeNote(View->SelectedNote);
  1317.                             }
  1318.                         View->SelectionMode = eTrackViewNoSelection;
  1319.                         View->InsertionPointIndex = View->SelectedNoteFrame;
  1320.                         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1321.                             PRERR(ForceAbort,"TrackViewDeleteSingleNote:  insertion point beyond end of track"));
  1322.                         EXECUTE(View->SelectedNote = (NoteObjectRec*)0x81818181;)
  1323.                         EXECUTE(View->SelectedNoteFrame = -1;)
  1324.                         /* redrawing everything is overkill and should be fixed */
  1325.                         TrackViewRedrawAll(View);
  1326.                         return;
  1327.                     }
  1328.             }
  1329.         EXECUTE(PRERR(AllowResume,"TrackViewDeleteSingleNote:  couldn't find the note"));
  1330.     }
  1331.  
  1332.  
  1333. /* add a track to the greyed-out background display */
  1334. MyBoolean                                TrackViewAddBackgroundTrack(TrackViewRec* View,
  1335.                                                     struct TrackObjectRec* TrackObj)
  1336.     {
  1337.         MyBoolean                            Result;
  1338.         long                                    FrameIndex;
  1339.         MyBoolean                            OnAFrameFlag;
  1340.  
  1341.         CheckPtrExistence(View);
  1342.         CheckPtrExistence(TrackObj);
  1343.         (void)TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,View->PixelIndent,
  1344.             &OnAFrameFlag,&FrameIndex);
  1345.         Result = AddTrackToDisplaySchedule(View->Schedule,TrackObj);
  1346.         if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  1347.             {
  1348.                 (void)TrackDisplayIndexToPixel(View->Schedule,0,FrameIndex,&(View->PixelIndent));
  1349.             }
  1350.          else
  1351.             {
  1352.                 View->PixelIndent = 0;
  1353.             }
  1354.         TrackViewRedrawAll(View);
  1355.         return Result;
  1356.     }
  1357.  
  1358.  
  1359. /* remove a track from the greyed-out background display */
  1360. void                                        TrackViewRemoveBackgroundTrack(TrackViewRec* View,
  1361.                                                     struct TrackObjectRec* TrackObj)
  1362.     {
  1363.         long                                    FrameIndex;
  1364.         MyBoolean                            OnAFrameFlag;
  1365.  
  1366.         CheckPtrExistence(View);
  1367.         CheckPtrExistence(TrackObj);
  1368.         (void)TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,View->PixelIndent,
  1369.             &OnAFrameFlag,&FrameIndex);
  1370.         DeleteTrackFromDisplaySchedule(View->Schedule,TrackObj);
  1371.         if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  1372.             {
  1373.                 (void)TrackDisplayIndexToPixel(View->Schedule,0,FrameIndex,&(View->PixelIndent));
  1374.             }
  1375.          else
  1376.             {
  1377.                 View->PixelIndent = 0;
  1378.             }
  1379.         TrackViewRedrawAll(View);
  1380.     }
  1381.  
  1382.  
  1383. /* present a dialog box for editing the selected object's attributes.  it is an */
  1384. /* error if there is no single note or command selected. */
  1385. void                                        TrackViewEditSingleSelectionAttributes(TrackViewRec* View)
  1386.     {
  1387.         CheckPtrExistence(View);
  1388.         TrackViewFlushUndoInfo(View);
  1389.         ERROR(!TrackViewIsASingleNoteSelected(View)
  1390.             && !TrackViewIsASingleCommandSelected(View),PRERR(ForceAbort,
  1391.             "TrackViewEditSingleSelectionAttributes:  no singly select object"));
  1392.         EditNoteOrCommandAttributes(View->SelectedNote,View->TrackObj);
  1393.     }
  1394.  
  1395.  
  1396. /* set a tie from the currently selected note to the note at the specified position. */
  1397. /* it is an error if there is no single note selected. */
  1398. void                                        TrackViewSetTieOnNote(TrackViewRec* View, OrdType X, OrdType Y)
  1399.     {
  1400.         MyBoolean                            ActuallyOnAFrame;
  1401.         long                                    Index;
  1402.         long                                    DestinationFrameIndex;
  1403.         NoteObjectRec*                DestinationNote;
  1404.         MyBoolean                            CommandFlag;
  1405.  
  1406.         CheckPtrExistence(View);
  1407.         TrackViewFlushUndoInfo(View);
  1408.         ERROR(View->SelectionMode != eTrackViewSingleNoteSelection,PRERR(ForceAbort,
  1409.             "TrackViewSetTieOnNote:  single note selection is false."));
  1410.         X -= View->XLoc;
  1411.         Y -= View->YLoc;
  1412.         /* figure out where we are supposed to put this note. */
  1413.         if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,X + View->PixelIndent,
  1414.             &ActuallyOnAFrame,&Index))
  1415.             {
  1416.                 return;
  1417.             }
  1418.  
  1419.         /* if they didn't click on anything, then cancel the tie */
  1420.         if (!ActuallyOnAFrame)
  1421.             {
  1422.                 goto DeleteTheTiePoint;
  1423.             }
  1424.  
  1425.         /* get the destination note */
  1426.         DestinationNote = TrackDisplayGetUnderlyingNote(View->Schedule,
  1427.             TrackDisplayGetTrackIndex(View->Schedule,View->TrackObj),&CommandFlag,
  1428.             X + View->PixelIndent,&DestinationFrameIndex);
  1429.  
  1430.         /* change the data */
  1431.         if ((DestinationFrameIndex <= View->SelectedNoteFrame) || (DestinationNote == NIL))
  1432.             {
  1433.                 /* delete the tie */
  1434.              DeleteTheTiePoint:
  1435.                 PutNoteTieTarget(View->SelectedNote,NIL);
  1436.                 TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1437.             }
  1438.          else
  1439.             {
  1440.                 /* create the tie */
  1441.                 /* patch the tie flag thing */
  1442.                 PutNoteTieTarget(View->SelectedNote,DestinationNote);
  1443.                 TrackObjectAltered(View->TrackObj,View->SelectedNoteFrame);
  1444.                 /* change selection */
  1445.                 View->SelectedNote = DestinationNote;
  1446.                 View->SelectedNoteFrame = DestinationFrameIndex;
  1447.             }
  1448.  
  1449.         /* redraw */
  1450.         TrackViewRedrawAll(View);
  1451.         View->CursorBarIsVisible = False; /* temporary */
  1452.     }
  1453.  
  1454.  
  1455. /* select a range of frames. */
  1456. void                                        TrackViewSetRangeSelection(TrackViewRec* View, long StartFrame,
  1457.                                                     long EndFramePlusOne)
  1458.     {
  1459.         CheckPtrExistence(View);
  1460.         ERROR(StartFrame >= EndFramePlusOne,PRERR(ForceAbort,
  1461.             "TrackViewSetRangeSelection:  frame boundaries are invalid"));
  1462.         ERROR(StartFrame < 0,PRERR(ForceAbort,
  1463.             "TrackViewSetRangeSelection:  start frame is before beginning of track"));
  1464.         ERROR(EndFramePlusOne > TrackObjectGetNumFrames(View->TrackObj),PRERR(ForceAbort,
  1465.             "TrackViewSetRangeSelection:  end frame is after end of track"));
  1466.         View->SelectionMode = eTrackViewRangeSelection;
  1467.         View->RangeSelectStart = StartFrame;
  1468.         View->RangeSelectEnd = EndFramePlusOne;
  1469.         /* redraw with the selection changes */
  1470.         TrackViewRedrawAll(View);
  1471.         View->CursorBarIsVisible = False; /* temporary */
  1472.     }
  1473.  
  1474.  
  1475. /* set an insertion point at the specified frame index */
  1476. void                                        TrackViewSetInsertionPoint(TrackViewRec* View, long FrameIndex)
  1477.     {
  1478.         CheckPtrExistence(View);
  1479.         ERROR((FrameIndex < 0) || (FrameIndex > TrackObjectGetNumFrames(View->TrackObj)),
  1480.             PRERR(ForceAbort,"TrackViewSetInsertionPoint:  index is out of range"));
  1481.         View->SelectionMode = eTrackViewNoSelection;
  1482.         View->InsertionPointIndex = FrameIndex;
  1483.         /* redraw with the selection changes */
  1484.         TrackViewRedrawAll(View);
  1485.         View->CursorBarIsVisible = False; /* temporary */
  1486.     }
  1487.  
  1488.  
  1489. /* do a mouse down, which may select things.  ExtendSelection is true for shift-key */
  1490. /* type selection extending */
  1491. void                                        TrackViewDoMouseDown(TrackViewRec* View, OrdType XLoc,
  1492.                                                     OrdType YLoc, MyBoolean ExtendSelection,
  1493.                                                     void (*ScrollCallback)(void* Refcon), void* Refcon)
  1494.     {
  1495.         MyBoolean                            LandedOnAFrame;
  1496.         long                                    ClickFrameIndex;
  1497.         long                                    BaseSelectStart;
  1498.         long                                    BaseSelectEnd;
  1499.         long                                    PreviousSelectStart;
  1500.         long                                    PreviousSelectEnd;
  1501.  
  1502.         CheckPtrExistence(View);
  1503.  
  1504.         /* if we are NOT extending the selection, then we need to set the insertion */
  1505.         /* point to the specified location */
  1506.         if (!ExtendSelection || ((View->SelectionMode != eTrackViewNoSelection)
  1507.             && (View->SelectionMode != eTrackViewRangeSelection)))
  1508.             {
  1509.                 if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,
  1510.                     XLoc - View->XLoc + View->PixelIndent,&LandedOnAFrame,&ClickFrameIndex))
  1511.                     {
  1512.                         return;
  1513.                     }
  1514.                 ERROR((ClickFrameIndex < 0) || (ClickFrameIndex
  1515.                     > TrackObjectGetNumFrames(View->TrackObj)),PRERR(ForceAbort,
  1516.                     "TrackViewDoMouseDown:  click frame index is beyond the bounds of the track"));
  1517.                 View->SelectionMode = eTrackViewNoSelection;
  1518.                 View->InsertionPointIndex = ClickFrameIndex;
  1519.                 ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1520.                     PRERR(ForceAbort,"TrackViewDoMouseDown:  insertion point beyond end of track"));
  1521.             }
  1522.         ERROR((View->SelectionMode != eTrackViewNoSelection) && (View->SelectionMode
  1523.             != eTrackViewRangeSelection),PRERR(ForceAbort,
  1524.             "TrackViewDoMouseDown:  bad selection mode"));
  1525.  
  1526.         /* now figure out where the existing selection boundaries are */
  1527.         if (View->SelectionMode == eTrackViewRangeSelection)
  1528.             {
  1529.                 BaseSelectStart = View->RangeSelectStart;
  1530.                 BaseSelectEnd = View->RangeSelectEnd;
  1531.             }
  1532.          else
  1533.             {
  1534.                 BaseSelectStart = View->InsertionPointIndex;
  1535.                 BaseSelectEnd = View->InsertionPointIndex;
  1536.             }
  1537.         PreviousSelectStart = BaseSelectStart;
  1538.         PreviousSelectEnd = BaseSelectEnd;
  1539.         if (BaseSelectStart < BaseSelectEnd)
  1540.             {
  1541.                 TrackViewSetRangeSelection(View,BaseSelectStart,BaseSelectEnd);
  1542.             }
  1543.          else
  1544.             {
  1545.                 TrackViewSetInsertionPoint(View,BaseSelectStart);
  1546.             }
  1547.  
  1548.         /* enter the selection tracking loop */
  1549.         do
  1550.             {
  1551.                 long                                    NewSelectStart;
  1552.                 long                                    NewSelectEnd;
  1553.  
  1554.                 /* scroll if necessary */
  1555.                 if (XLoc - View->XLoc < 0)
  1556.                     {
  1557.                         /* scroll left */
  1558.                         TrackViewSetNewHorizontalOffset(View,TrackViewGetHorizontalOffset(
  1559.                             View) - (1 * GetTrackViewWidth(View)) / 8);
  1560.                         ScrollCallback(Refcon);
  1561.                     }
  1562.                 if (XLoc - View->XLoc >= View->Width)
  1563.                     {
  1564.                         /* scroll right */
  1565.                         TrackViewSetNewHorizontalOffset(View,TrackViewGetHorizontalOffset(
  1566.                             View) + (1 * GetTrackViewWidth(View)) / 8);
  1567.                         ScrollCallback(Refcon);
  1568.                     }
  1569.                 if (YLoc - View->YLoc < 0)
  1570.                     {
  1571.                         /* scroll up */
  1572.                         TrackViewSetNewVerticalOffset(View,TrackViewGetVerticalOffset(
  1573.                             View) - (1 * GetTrackViewHeight(View)) / 8);
  1574.                         ScrollCallback(Refcon);
  1575.                     }
  1576.                 if (YLoc - View->YLoc >= View->Height)
  1577.                     {
  1578.                         /* scroll down */
  1579.                         TrackViewSetNewVerticalOffset(View,TrackViewGetVerticalOffset(
  1580.                             View) + (1 * GetTrackViewHeight(View)) / 8);
  1581.                         ScrollCallback(Refcon);
  1582.                     }
  1583.  
  1584.                 /* figure out where the thang goes now */
  1585.                 if (!TrackDisplayPixelToIndex(View->Schedule,View->TrackObj,
  1586.                     XLoc - View->XLoc + View->PixelIndent,&LandedOnAFrame,&ClickFrameIndex))
  1587.                     {
  1588.                         return;
  1589.                     }
  1590.                 ERROR((ClickFrameIndex < 0) || (ClickFrameIndex
  1591.                     > TrackObjectGetNumFrames(View->TrackObj)),PRERR(ForceAbort,
  1592.                     "TrackViewDoMouseDown:  click frame index is beyond the bounds of the track"));
  1593.                 NewSelectStart = BaseSelectStart;
  1594.                 NewSelectEnd = BaseSelectEnd;
  1595.                 if (ClickFrameIndex < NewSelectStart)
  1596.                     {
  1597.                         NewSelectStart = ClickFrameIndex;
  1598.                     }
  1599.                 if (ClickFrameIndex > NewSelectEnd)
  1600.                     {
  1601.                         NewSelectEnd = ClickFrameIndex;
  1602.                     }
  1603.                 if ((NewSelectStart != PreviousSelectStart)
  1604.                     || (NewSelectEnd != PreviousSelectEnd))
  1605.                     {
  1606.                         PreviousSelectStart = NewSelectStart;
  1607.                         PreviousSelectEnd = NewSelectEnd;
  1608.                         if (NewSelectStart < NewSelectEnd)
  1609.                             {
  1610.                                 TrackViewSetRangeSelection(View,NewSelectStart,NewSelectEnd);
  1611.                             }
  1612.                          else
  1613.                             {
  1614.                                 TrackViewSetInsertionPoint(View,NewSelectStart);
  1615.                             }
  1616.                     }
  1617.             } while (eMouseUp != GetAnEvent(&XLoc,&YLoc,NIL,NIL,NIL,NIL));
  1618.     }
  1619.  
  1620.  
  1621. /* set the range selection to the entire track */
  1622. void                                        TrackViewSelectAll(TrackViewRec* View)
  1623.     {
  1624.         long                                    NumFrames;
  1625.  
  1626.         CheckPtrExistence(View);
  1627.         NumFrames = TrackObjectGetNumFrames(View->TrackObj);
  1628.         if (NumFrames > 0)
  1629.             {
  1630.                 View->SelectionMode = eTrackViewRangeSelection;
  1631.                 View->RangeSelectStart = 0;
  1632.                 View->RangeSelectEnd = NumFrames;
  1633.             }
  1634.          else
  1635.             {
  1636.                 View->SelectionMode = eTrackViewNoSelection;
  1637.                 View->InsertionPointIndex = 0;
  1638.             }
  1639.         /* redraw with the selection changes */
  1640.         TrackViewRedrawAll(View);
  1641.         View->CursorBarIsVisible = False; /* temporary */
  1642.     }
  1643.  
  1644.  
  1645. /* delete the selected range.  it is an error if there is no selected range. it */
  1646. /* returns False if it fails.  undo information is automatically maintained */
  1647. MyBoolean                                TrackViewDeleteRangeSelection(TrackViewRec* View)
  1648.     {
  1649.         CheckPtrExistence(View);
  1650.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1651.             "TrackViewDeleteRangeSelection:  called with no range selected"));
  1652.         TrackViewFlushUndoInfo(View);
  1653.         if (!TrackViewBuildFullUndoBackingStore(View))
  1654.             {
  1655.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  1656.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  1657.                     {
  1658.                         default:
  1659.                             EXECUTE(PRERR(ForceAbort,
  1660.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  1661.                             break;
  1662.                         case eYes:
  1663.                             break;
  1664.                         case eNo:
  1665.                             return False; /* abort now */
  1666.                     }
  1667.             }
  1668.  
  1669.         /* delete the stuff */
  1670.         TrackObjectDeleteFrameRun(View->TrackObj,View->RangeSelectStart,
  1671.             View->RangeSelectEnd - View->RangeSelectStart);
  1672.         View->SelectionMode = eTrackViewNoSelection;
  1673.         View->InsertionPointIndex = View->RangeSelectStart;
  1674.         ERROR(View->InsertionPointIndex > TrackObjectGetNumFrames(View->TrackObj),
  1675.             PRERR(ForceAbort,"TrackViewDeleteRangeSelection:  insertion point beyond end of track"));
  1676.  
  1677.         /* redraw with changes */
  1678.         TrackViewRedrawAll(View);
  1679.         View->CursorBarIsVisible = False; /* temporary */
  1680.         TrackViewShowSelection(View);
  1681.  
  1682.         return True;
  1683.     }
  1684.  
  1685.  
  1686. /* attempt to paste notes into the track.  returns False if it fails.  undo */
  1687. /* information is automatically maintained. */
  1688. MyBoolean                                TrackViewAttemptPaste(TrackViewRec* View)
  1689.     {
  1690.         char*                                    Scrap;
  1691.         MyBoolean                            TotalSuccessFlag = False;
  1692.  
  1693.         CheckPtrExistence(View);
  1694.         TrackViewFlushUndoInfo(View);
  1695.         if (View->SelectionMode == eTrackViewRangeSelection)
  1696.             {
  1697.                 if (!TrackViewDeleteRangeSelection(View))
  1698.                     {
  1699.                         return False;
  1700.                     }
  1701.             }
  1702.         ERROR(View->SelectionMode != eTrackViewNoSelection,PRERR(ForceAbort,
  1703.             "TrackViewAttemptPaste:  no insertion point"));
  1704.         Scrap = GetCopyOfScrap();
  1705.         if (Scrap != NIL)
  1706.             {
  1707.                 if ((PtrSize(Scrap) >= sizeof(MAGICSCRAPSTRING))
  1708.                     && MemEqu(MAGICSCRAPSTRING,Scrap,sizeof(MAGICSCRAPSTRING)))
  1709.                     {
  1710.                         FileSpec*                            TempFileLoc;
  1711.  
  1712.                         TempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1713.                             CODE4BYTES('\?','\?','\?','\?'));
  1714.                         if (TempFileLoc != NIL)
  1715.                             {
  1716.                                 FileType*                            FileDesc;
  1717.  
  1718.                                 if (OpenFile(TempFileLoc,&FileDesc,eReadAndWrite))
  1719.                                     {
  1720.                                         if (0 == WriteToFile(FileDesc,Scrap + sizeof(MAGICSCRAPSTRING),
  1721.                                             PtrSize(Scrap) - sizeof(MAGICSCRAPSTRING)))
  1722.                                             {
  1723.                                                 if (SetFilePosition(FileDesc,0))
  1724.                                                     {
  1725.                                                         BufferedInputRec*        BuffFile;
  1726.  
  1727.                                                         BuffFile = NewBufferedInput(FileDesc);
  1728.                                                         if (BuffFile != NIL)
  1729.                                                             {
  1730.                                                                 ArrayRec*                        FrameArray EXECUTE(= (ArrayRec*)0x81818181);
  1731.  
  1732.                                                                 if (eFileLoadNoError == ReadNoteVector(&FrameArray,BuffFile))
  1733.                                                                     {
  1734.                                                                         long                                Scan;
  1735.  
  1736.                                                                         CheckPtrExistence(FrameArray);
  1737.                                                                         Scan = 0;
  1738.                                                                         while (ArrayGetLength(FrameArray) > 0)
  1739.                                                                             {
  1740.                                                                                 FrameObjectRec*            Thing;
  1741.  
  1742.                                                                                 Thing = (FrameObjectRec*)ArrayGetElement(
  1743.                                                                                     FrameArray,0);
  1744.                                                                                 if (!TrackObjectInsertFrame(View->TrackObj,
  1745.                                                                                     Scan + View->InsertionPointIndex,Thing))
  1746.                                                                                     {
  1747.                                                                                         long                                Limit;
  1748.  
  1749.                                                                                         /* delete all the ones we added */
  1750.                                                                                         TrackObjectDeleteFrameRun(View->TrackObj,
  1751.                                                                                             View->InsertionPointIndex,Scan);
  1752.                                                                                         /* delete the ones we didn't add */
  1753.                                                                                         Limit = ArrayGetLength(FrameArray);
  1754.                                                                                         for (Scan = 0; Scan < Limit; Scan += 1)
  1755.                                                                                             {
  1756.                                                                                                 DisposeFrameAndContents(
  1757.                                                                                                     (FrameObjectRec*)ArrayGetElement(
  1758.                                                                                                     FrameArray,Scan));
  1759.                                                                                             }
  1760.                                                                                         goto ExitPoint;
  1761.                                                                                     }
  1762.                                                                                 ArrayDeleteElement(FrameArray,0);
  1763.                                                                                 Scan += 1;
  1764.                                                                             }
  1765.                                                                         /* remember undo information */
  1766.                                                                         View->UndoState = eTrackViewUndoRangeInsertion;
  1767.                                                                         View->UndoRangeStartIndex = View->InsertionPointIndex;
  1768.                                                                         View->UndoRangeElemCount = Scan;
  1769.                                                                         /* update display parameters */
  1770.                                                                         View->InsertionPointIndex += Scan;
  1771.                                                                         ERROR(View->InsertionPointIndex
  1772.                                                                             > TrackObjectGetNumFrames(View->TrackObj),
  1773.                                                                             PRERR(ForceAbort,"TrackViewAttemptPaste:  "
  1774.                                                                             "insertion point beyond end of track"));
  1775.                                                                         TotalSuccessFlag = True;
  1776.                                                                         TrackViewRedrawAll(View);
  1777.                                                                         View->CursorBarIsVisible = False; /* temporary */
  1778.                                                                         TrackViewShowSelection(View);
  1779.                                                                         /* jump here when something bad happens */
  1780.                                                                      ExitPoint:
  1781.                                                                         DisposeArray(FrameArray);
  1782.                                                                     }
  1783.                                                                 EndBufferedInput(BuffFile);
  1784.                                                             }
  1785.                                                     }
  1786.                                             }
  1787.                                         CloseFile(FileDesc);
  1788.                                     }
  1789.                                 DeleteFile(TempFileLoc);
  1790.                                 DisposeFileSpec(TempFileLoc);
  1791.                             }
  1792.                     }
  1793.                 ReleasePtr(Scrap);
  1794.             }
  1795.         return TotalSuccessFlag;
  1796.     }
  1797.  
  1798.  
  1799. /* copy the selected range to the clipboard.  it is an error if there is no selected */
  1800. /* range.  it returns True if successful. */
  1801. MyBoolean                                TrackViewCopyRangeSelection(TrackViewRec* View)
  1802.     {
  1803.         MyBoolean                            TotalSuccessFlag;
  1804.         ArrayRec*                            CopyOfSelection;
  1805.  
  1806.         CheckPtrExistence(View);
  1807.         ERROR(View->SelectionMode != eTrackViewRangeSelection,PRERR(ForceAbort,
  1808.             "TrackViewDeleteRangeSelection:  called with no range selected"));
  1809.         TrackViewFlushUndoInfo(View);
  1810.         CopyOfSelection = TrackObjectCopyFrameRun(View->TrackObj,View->RangeSelectStart,
  1811.             View->RangeSelectEnd - View->RangeSelectStart);
  1812.         if (CopyOfSelection != NIL)
  1813.             {
  1814.                 long                                    Limit;
  1815.                 long                                    Scan;
  1816.                 FileSpec*                            TempFileLoc;
  1817.  
  1818.                 TempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1819.                     CODE4BYTES('\?','\?','\?','\?'));
  1820.                 if (TempFileLoc != NIL)
  1821.                     {
  1822.                         FileType*                            FileDesc;
  1823.  
  1824.                         if (OpenFile(TempFileLoc,&FileDesc,eReadAndWrite))
  1825.                             {
  1826.                                 BufferedOutputRec*        BuffOut;
  1827.  
  1828.                                 BuffOut = NewBufferedOutput(FileDesc);
  1829.                                 if (BuffOut != NIL)
  1830.                                     {
  1831.                                         MyBoolean                            WriteSucceeded = False;
  1832.  
  1833.                                         if (WriteBufferedOutput(BuffOut,sizeof(MAGICSCRAPSTRING),
  1834.                                             MAGICSCRAPSTRING))
  1835.                                             {
  1836.                                                 if (eFileLoadNoError == WriteNoteVector(CopyOfSelection,BuffOut))
  1837.                                                     {
  1838.                                                         WriteSucceeded = True;
  1839.                                                     }
  1840.                                             }
  1841.                                         if (EndBufferedOutput(BuffOut) && WriteSucceeded)
  1842.                                             {
  1843.                                                 if (SetFilePosition(FileDesc,0))
  1844.                                                     {
  1845.                                                         char*                                    Scrap;
  1846.  
  1847.                                                         Scrap = AllocPtrCanFail(GetFileLength(FileDesc),
  1848.                                                             "TrackViewCopyRangeSelection:  scrap temp");
  1849.                                                         if (Scrap != NIL)
  1850.                                                             {
  1851.                                                                 if (0 == ReadFromFile(FileDesc,Scrap,PtrSize(Scrap)))
  1852.                                                                     {
  1853.                                                                         if (SetScrapToThis(Scrap))
  1854.                                                                             {
  1855.                                                                                 TotalSuccessFlag = True;
  1856.                                                                             }
  1857.                                                                     }
  1858.                                                                 ReleasePtr(Scrap);
  1859.                                                             }
  1860.                                                     }
  1861.                                             }
  1862.                                     }
  1863.                                 CloseFile(FileDesc);
  1864.                             }
  1865.                         DeleteFile(TempFileLoc);
  1866.                         DisposeFileSpec(TempFileLoc);
  1867.                     }
  1868.                 Limit = ArrayGetLength(CopyOfSelection);
  1869.                 for (Scan = 0; Scan < Limit; Scan += 1)
  1870.                     {
  1871.                         DisposeFrameAndContents((FrameObjectRec*)ArrayGetElement(
  1872.                             CopyOfSelection,Scan));
  1873.                     }
  1874.                 DisposeArray(CopyOfSelection);
  1875.             }
  1876.         return TotalSuccessFlag;
  1877.     }
  1878.  
  1879.  
  1880. /* cut the range selection (copy to clipboard, then delete).  returns True if */
  1881. /* successful.  it is an error if there is no range selected.  automatically */
  1882. /* updates undo information. */
  1883. MyBoolean                                TrackViewCutRangeSelection(TrackViewRec* View)
  1884.     {
  1885.         CheckPtrExistence(View);
  1886.         TrackViewFlushUndoInfo(View);
  1887.         if (TrackViewCopyRangeSelection(View))
  1888.             {
  1889.                 if (TrackViewDeleteRangeSelection(View))
  1890.                     {
  1891.                         return True;
  1892.                     }
  1893.             }
  1894.         return False;
  1895.     }
  1896.  
  1897.  
  1898. /* show the selection or insertion point by scrolling the view area */
  1899. void                                        TrackViewShowSelection(TrackViewRec* View)
  1900.     {
  1901.         long                                    CenteringIndex;
  1902.         long                                    PixelIndex;
  1903.  
  1904.         CheckPtrExistence(View);
  1905.         switch (View->SelectionMode)
  1906.             {
  1907.                 default:
  1908.                     EXECUTE(PRERR(ForceAbort,"TrackViewShowSelection:  illegal selection mode"));
  1909.                     break;
  1910.                 case eTrackViewNoSelection:
  1911.                     CenteringIndex = View->InsertionPointIndex;
  1912.                     break;
  1913.                 case eTrackViewSingleNoteSelection:
  1914.                 case eTrackViewSingleCommandSelection:
  1915.                     CenteringIndex = View->SelectedNoteFrame;
  1916.                     break;
  1917.                 case eTrackViewRangeSelection:
  1918.                     CenteringIndex = View->RangeSelectStart;
  1919.                     break;
  1920.             }
  1921.         if (CenteringIndex < TrackObjectGetNumFrames(View->TrackObj))
  1922.             {
  1923.                 if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  1924.                     CenteringIndex,&PixelIndex))
  1925.                     {
  1926.                         return;
  1927.                     }
  1928.             }
  1929.         else if (TrackObjectGetNumFrames(View->TrackObj) > 0)
  1930.             {
  1931.                 if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  1932.                     CenteringIndex - 1,&PixelIndex))
  1933.                     {
  1934.                         return;
  1935.                     }
  1936.             }
  1937.         else
  1938.             {
  1939.                 /* no frames at all. */
  1940.                 PixelIndex = 0;
  1941.             }
  1942.         PixelIndex -= View->Width / 2;
  1943.         if (PixelIndex < 0)
  1944.             {
  1945.                 PixelIndex = 0;
  1946.             }
  1947.         TrackViewSetNewHorizontalOffset(View,PixelIndex);
  1948.     }
  1949.  
  1950.  
  1951. /* find out if we can undo the last operation */
  1952. MyBoolean                                TrackViewCanWeUndo(TrackViewRec* View)
  1953.     {
  1954.         CheckPtrExistence(View);
  1955.         return (eTrackViewNoUndo != View->UndoState);
  1956.     }
  1957.  
  1958.  
  1959. /* dispose of all undo information. */
  1960. void                                        TrackViewFlushUndoInfo(TrackViewRec* View)
  1961.     {
  1962.         CheckPtrExistence(View);
  1963.         switch (View->UndoState)
  1964.             {
  1965.                 default:
  1966.                     EXECUTE(PRERR(ForceAbort,"TrackViewFlushUndoInfo:  bad undo state"));
  1967.                     break;
  1968.                 case eTrackViewNoUndo:
  1969.                 case eTrackViewUndoNoteInsertion:
  1970.                 case eTrackViewUndoRangeInsertion:
  1971.                     break;
  1972.                 case eTrackViewUndoFromFile:
  1973.                     CloseFile(View->UndoTempFileDesc);
  1974.                     DeleteFile(View->UndoTempFileLoc);
  1975.                     DisposeFileSpec(View->UndoTempFileLoc);
  1976.                     break;
  1977.             }
  1978.         View->UndoState = eTrackViewNoUndo;
  1979.     }
  1980.  
  1981.  
  1982. /* save the undo information for the track.  returns False if it fails. */
  1983. MyBoolean                                TrackViewBuildFullUndoBackingStore(TrackViewRec* View)
  1984.     {
  1985.         BufferedOutputRec*        Output;
  1986.  
  1987.         CheckPtrExistence(View);
  1988.         TrackViewFlushUndoInfo(View);
  1989.         ERROR(View->UndoState != eTrackViewNoUndo,PRERR(ForceAbort,
  1990.             "TrackViewBuildFullUndoBackingStore:  expected undo information to be purged"));
  1991.         /* make backups (see, even my programs do it!) */
  1992.         View->UndoTempFileLoc = NewTempFileSpec(CODE4BYTES('\?','\?','\?','\?'),
  1993.             CODE4BYTES('\?','\?','\?','\?'));
  1994.         if (View->UndoTempFileLoc == NIL)
  1995.             {
  1996.              FailurePoint1:
  1997.                 return False;
  1998.             }
  1999.         if (!OpenFile(View->UndoTempFileLoc,&(View->UndoTempFileDesc),eReadAndWrite))
  2000.             {
  2001.              FailurePoint2:
  2002.                 DeleteFile(View->UndoTempFileLoc);
  2003.                 DisposeFileSpec(View->UndoTempFileLoc);
  2004.                 goto FailurePoint1;
  2005.             }
  2006.         Output = NewBufferedOutput(View->UndoTempFileDesc);
  2007.         if (Output == NIL)
  2008.             {
  2009.              FailurePoint3:
  2010.                 CloseFile(View->UndoTempFileDesc);
  2011.                 goto FailurePoint2;
  2012.             }
  2013.         if (!TrackObjectWriteNotesOutToFile(View->TrackObj,Output))
  2014.             {
  2015.              FailurePoint3a:
  2016.                 EndBufferedOutput(Output);
  2017.                 goto FailurePoint3;
  2018.             }
  2019.         if (!EndBufferedOutput(Output))
  2020.             {
  2021.              FailurePoint4:
  2022.                 goto FailurePoint3;
  2023.             }
  2024.         View->UndoState = eTrackViewUndoFromFile;
  2025.         return True;
  2026.     }
  2027.  
  2028.  
  2029. /* undo the last operation.  if it fails, well... */
  2030. void                                        TrackViewUndo(TrackViewRec* View)
  2031.     {
  2032.         UndoChoices                        LocalUndoState;
  2033.         long                                    LocalUndoNoteInsertionFrameIndex;
  2034.         long                                    LocalUndoNoteInsertionNoteIndex;
  2035.         long                                    LocalUndoRangeStartIndex;
  2036.         long                                    LocalUndoRangeElemCount;
  2037.         FileSpec*                            LocalUndoTempFileLoc;
  2038.         FileType*                            LocalUndoTempFileDesc;
  2039.  
  2040.         CheckPtrExistence(View);
  2041.         /* first, make a backup of the undo information, so we can undo the undo */
  2042.         LocalUndoState = View->UndoState;
  2043.         LocalUndoNoteInsertionFrameIndex = View->UndoNoteInsertionFrameIndex;
  2044.         LocalUndoNoteInsertionNoteIndex = View->UndoNoteInsertionNoteIndex;
  2045.         LocalUndoRangeStartIndex = View->UndoRangeStartIndex;
  2046.         LocalUndoRangeElemCount = View->UndoRangeElemCount;
  2047.         LocalUndoTempFileLoc = View->UndoTempFileLoc;
  2048.         LocalUndoTempFileDesc = View->UndoTempFileDesc;
  2049.         /* reset the undo state */
  2050.         View->UndoState = eTrackViewNoUndo;
  2051.         /* build backup for our undo */
  2052.         if (!TrackViewBuildFullUndoBackingStore(View))
  2053.             {
  2054.                 switch (AskYesNoCancel("There is not enough disk space available to preserve "
  2055.                     "undo information.  Continue?",NIL,"Continue","Cancel",NIL))
  2056.                     {
  2057.                         default:
  2058.                             EXECUTE(PRERR(ForceAbort,
  2059.                                 "TrackViewDeleteSingleNoteOrCommand:  bad value from AskYesNoCancel"));
  2060.                             break;
  2061.                         case eYes:
  2062.                             /* continue */
  2063.                             break;
  2064.                         case eNo:
  2065.                             /* abort now -- restore the undo information */
  2066.                             View->UndoState = LocalUndoState;
  2067.                             View->UndoNoteInsertionFrameIndex = LocalUndoNoteInsertionFrameIndex;
  2068.                             View->UndoNoteInsertionNoteIndex = LocalUndoNoteInsertionNoteIndex;
  2069.                             View->UndoRangeStartIndex = LocalUndoRangeStartIndex;
  2070.                             View->UndoRangeElemCount = LocalUndoRangeElemCount;
  2071.                             View->UndoTempFileLoc = LocalUndoTempFileLoc;
  2072.                             View->UndoTempFileDesc = LocalUndoTempFileDesc;
  2073.                             return;
  2074.                     }
  2075.             }
  2076.         /* do the undoing */
  2077.         switch (LocalUndoState)
  2078.             {
  2079.                 default:
  2080.                     EXECUTE(PRERR(ForceAbort,"TrackViewUndo:  bad undo state"));
  2081.                     break;
  2082.                 case eTrackViewUndoNoteInsertion:
  2083.                     /* delete the note */
  2084.                     {
  2085.                         FrameObjectRec*            Frame;
  2086.  
  2087.                         Frame = TrackObjectGetFrame(View->TrackObj,LocalUndoNoteInsertionFrameIndex);
  2088.                         if (NumNotesInFrame(Frame) == 1)
  2089.                             {
  2090.                                 /* delete whole frame */
  2091.                                 TrackObjectDeleteFrameRun(View->TrackObj,
  2092.                                     LocalUndoNoteInsertionFrameIndex,1);
  2093.                             }
  2094.                          else
  2095.                             {
  2096.                                 NoteObjectRec*            Note;
  2097.  
  2098.                                 /* just delete a note from the frame */
  2099.                                 Note = GetNoteFromFrame(Frame,LocalUndoNoteInsertionNoteIndex);
  2100.                                 if (!IsItACommand(Note))
  2101.                                     {
  2102.                                         TrackObjectNullifyTies(View->TrackObj,Note);
  2103.                                     }
  2104.                                 DeleteNoteFromFrame(Frame,LocalUndoNoteInsertionNoteIndex);
  2105.                             }
  2106.                     }
  2107.                     break;
  2108.                 case eTrackViewUndoRangeInsertion:
  2109.                     TrackObjectDeleteFrameRun(View->TrackObj,LocalUndoRangeStartIndex,
  2110.                         LocalUndoRangeElemCount);
  2111.                     break;
  2112.                 case eTrackViewUndoFromFile:
  2113.                     /* recover all the notes from the file */
  2114.                     if (SetFilePosition(LocalUndoTempFileDesc,0))
  2115.                         {
  2116.                             BufferedInputRec*            Input;
  2117.  
  2118.                             Input = NewBufferedInput(LocalUndoTempFileDesc);
  2119.                             if (Input != NIL)
  2120.                                 {
  2121.                                     if (TrackObjectRecoverNotesFromFile(View->TrackObj,Input))
  2122.                                         {
  2123.                                             /* successful */
  2124.                                         }
  2125.                                     EndBufferedInput(Input);
  2126.                                 }
  2127.                         }
  2128.                     CloseFile(LocalUndoTempFileDesc);
  2129.                     DeleteFile(LocalUndoTempFileLoc);
  2130.                     DisposeFileSpec(LocalUndoTempFileLoc);
  2131.                     break;
  2132.             }
  2133.         TrackViewRedrawAll(View);
  2134.         View->CursorBarIsVisible = False; /* temporary */
  2135.     }
  2136.  
  2137.  
  2138. /* transpose the selection by adding AddHalfSteps to the pitch of each selected note */
  2139. /* AddHalfSteps can be negative.  it is an error if there is no single note selection */
  2140. /* or no range selection */
  2141. void                                        TrackViewTransposeSelection(TrackViewRec* View, long AddHalfSteps)
  2142.     {
  2143.         CheckPtrExistence(View);
  2144.         TrackViewFlushUndoInfo(View);
  2145.         if (TrackViewIsASingleNoteSelected(View))
  2146.             {
  2147.                 long                                    NewPitch;
  2148.  
  2149.                 NewPitch = GetNotePitch(View->SelectedNote) + AddHalfSteps;
  2150.                 if (NewPitch < 0)
  2151.                     {
  2152.                         NewPitch = 0;
  2153.                     }
  2154.                 else if (NewPitch > NUMNOTES - 1)
  2155.                     {
  2156.                         NewPitch = NUMNOTES - 1;
  2157.                     }
  2158.                 PutNotePitch(View->SelectedNote,NewPitch);
  2159.                 switch (NewPitch % 12)
  2160.                     {
  2161.                         case 0: /* C */
  2162.                         case 2: /* D */
  2163.                         case 4: /* E */
  2164.                         case 5: /* F */
  2165.                         case 7: /* G */
  2166.                         case 9: /* A */
  2167.                         case 11: /* B */
  2168.                             PutNoteFlatOrSharpStatus(View->SelectedNote,0);
  2169.                             break;
  2170.                         case 1: /* C# / Db */
  2171.                         case 3: /* D# / Eb */
  2172.                         case 6: /* F# / Gb */
  2173.                         case 8: /* G# / Ab */
  2174.                         case 10: /* A# / Bb */
  2175.                             if (AddHalfSteps >= 0)
  2176.                                 {
  2177.                                     if (GetNoteFlatOrSharpStatus(View->SelectedNote) == eFlatModifier)
  2178.                                         {
  2179.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eFlatModifier);
  2180.                                         }
  2181.                                      else
  2182.                                         {
  2183.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eSharpModifier);
  2184.                                         }
  2185.                                 }
  2186.                              else
  2187.                                 {
  2188.                                     if (GetNoteFlatOrSharpStatus(View->SelectedNote) == eSharpModifier)
  2189.                                         {
  2190.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eSharpModifier);
  2191.                                         }
  2192.                                      else
  2193.                                         {
  2194.                                             PutNoteFlatOrSharpStatus(View->SelectedNote,eFlatModifier);
  2195.                                         }
  2196.                                 }
  2197.                             break;
  2198.                     }
  2199.             }
  2200.         else if (TrackViewIsARangeSelected(View))
  2201.             {
  2202.                 long                                    FrameScan;
  2203.  
  2204.                 for (FrameScan = View->RangeSelectStart; FrameScan < View->RangeSelectEnd;
  2205.                     FrameScan += 1)
  2206.                     {
  2207.                         FrameObjectRec*                Frame;
  2208.  
  2209.                         Frame = TrackObjectGetFrame(View->TrackObj,FrameScan);
  2210.                         CheckPtrExistence(Frame);
  2211.                         if (!IsThisACommandFrame(Frame))
  2212.                             {
  2213.                                 long                                    NoteScan;
  2214.                                 long                                    NoteLimit;
  2215.  
  2216.                                 NoteLimit = NumNotesInFrame(Frame);
  2217.                                 for (NoteScan = 0; NoteScan < NoteLimit; NoteScan += 1)
  2218.                                     {
  2219.                                         NoteObjectRec*                Note;
  2220.                                         long                                    NewPitch;
  2221.  
  2222.                                         Note = GetNoteFromFrame(Frame,NoteScan);
  2223.                                         CheckPtrExistence(Note);
  2224.                                         NewPitch = GetNotePitch(Note) + AddHalfSteps;
  2225.                                         if (NewPitch < 0)
  2226.                                             {
  2227.                                                 NewPitch = 0;
  2228.                                             }
  2229.                                         else if (NewPitch > NUMNOTES - 1)
  2230.                                             {
  2231.                                                 NewPitch = NUMNOTES - 1;
  2232.                                             }
  2233.                                         PutNotePitch(Note,NewPitch);
  2234.                                         switch (NewPitch % 12)
  2235.                                             {
  2236.                                                 case 0: /* C */
  2237.                                                 case 2: /* D */
  2238.                                                 case 4: /* E */
  2239.                                                 case 5: /* F */
  2240.                                                 case 7: /* G */
  2241.                                                 case 9: /* A */
  2242.                                                 case 11: /* B */
  2243.                                                     PutNoteFlatOrSharpStatus(Note,0);
  2244.                                                     break;
  2245.                                                 case 1: /* C# / Db */
  2246.                                                 case 3: /* D# / Eb */
  2247.                                                 case 6: /* F# / Gb */
  2248.                                                 case 8: /* G# / Ab */
  2249.                                                 case 10: /* A# / Bb */
  2250.                                                     if (AddHalfSteps >= 0)
  2251.                                                         {
  2252.                                                             if (GetNoteFlatOrSharpStatus(Note) == eFlatModifier)
  2253.                                                                 {
  2254.                                                                     PutNoteFlatOrSharpStatus(Note,eFlatModifier);
  2255.                                                                 }
  2256.                                                              else
  2257.                                                                 {
  2258.                                                                     PutNoteFlatOrSharpStatus(Note,eSharpModifier);
  2259.                                                                 }
  2260.                                                         }
  2261.                                                      else
  2262.                                                         {
  2263.                                                             if (GetNoteFlatOrSharpStatus(Note) == eSharpModifier)
  2264.                                                                 {
  2265.                                                                     PutNoteFlatOrSharpStatus(Note,eSharpModifier);
  2266.                                                                 }
  2267.                                                              else
  2268.                                                                 {
  2269.                                                                     PutNoteFlatOrSharpStatus(Note,eFlatModifier);
  2270.                                                                 }
  2271.                                                         }
  2272.                                                     break;
  2273.                                             }
  2274.                                     }
  2275.                             }
  2276.                     }
  2277.             }
  2278.         else
  2279.             {
  2280.                 EXECUTE(PRERR(ForceAbort,"TrackViewTransposeSelection:  improper selection"));
  2281.             }
  2282.         TrackViewRedrawAll(View);
  2283.         View->CursorBarIsVisible = False; /* temporary */
  2284.         TrackObjectAltered(View->TrackObj,0);
  2285.     }
  2286.  
  2287.  
  2288. /* scroll to the specified measure.  invalid measure numbers may be specified. */
  2289. void                                        TrackViewShowMeasure(TrackViewRec* View, long MeasureNumber)
  2290.     {
  2291.         long                                    FrameIndex;
  2292.  
  2293.         CheckPtrExistence(View);
  2294.         if (!TrackDisplayMeasureIndexToFrame(View->Schedule,MeasureNumber,&FrameIndex))
  2295.             {
  2296.                 ErrorBeep();
  2297.             }
  2298.          else
  2299.             {
  2300.                 long                                    PixelIndex;
  2301.  
  2302.                 if (FrameIndex < TrackObjectGetNumFrames(View->TrackObj))
  2303.                     {
  2304.                         if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  2305.                             FrameIndex,&PixelIndex))
  2306.                             {
  2307.                                 return;
  2308.                             }
  2309.                     }
  2310.                 else if (TrackObjectGetNumFrames(View->TrackObj) > 0)
  2311.                     {
  2312.                         if (!TrackDisplayIndexToPixel(View->Schedule,0/*first track*/,
  2313.                             FrameIndex - 1,&PixelIndex))
  2314.                             {
  2315.                                 return;
  2316.                             }
  2317.                     }
  2318.                 else
  2319.                     {
  2320.                         /* no frames at all. */
  2321.                         PixelIndex = 0;
  2322.                     }
  2323.                 PixelIndex -= (View->Width / 3);
  2324.                 if (PixelIndex < 0)
  2325.                     {
  2326.                         PixelIndex = 0;
  2327.                     }
  2328.                 TrackViewSetNewHorizontalOffset(View,PixelIndex);
  2329.             }
  2330.     }
  2331.